当前位置:网站首页>反射(一)

反射(一)

2022-07-04 17:48:00 Cold Snowflakes

Properties

void load(InputStream inStream)
void load(Reader reader)
void store(OutputStream out,String comments)
void store(Writer writer,String comments)

读取文件内容

        Properties properties = new Properties();
        properties.load(new FileInputStream("idea_test\\src\\re.properties"));
        String classfullpath = properties.getProperty("classfullpath");		// 读取 导入进来的信息
        String methodName = properties.getProperty("method");

写入文件内容

        Properties prop = new Properties();
        prop.setProperty("001","林青霞");
        prop.setProperty("002","张曼玉");
        prop.setProperty("003","王祖贤");

        prop.store(new FileWriter("idea_test\\src\\re.txt"),null);

类加载

当程序要使用某个类时,如果该类还未被加载到内存,则系统会通过类的加载,类的连接,类的初始化这三个步骤来对类进行初始化。
一般情况下,JVM将会连续完成这三个步骤,所以有时也把这三个步骤统称为类加载。

类的加载:将 .class 文件读入内存,并为之创建一个Class类的实例。

类的连接
验证阶段:确保 .class 文件的字节流中包含信息符合当前虚拟机要求,不会危害虚拟机自身安全。
准备阶段:为static修饰的字段变量分配内存并且设置初始值为0,不包含用final修饰的static,因为final在编译的时候就会分配了。
解析阶段:主要将常量池中的符号引用替换为直接引用的过程。

类的初始化:类加载最后阶段,若该类具有超类,则对其进行初始化,执行静态初始化器和静态初始化成员变量(如前面只初始化了默认值的static变量将会在这个阶段赋值,成员变量也将被初始化)。

        // 传统创建对象的方式
        Cat cat = new Cat();
        cat.hi();


        // 根据 配置文件指定的信息, 创建对象
        Properties properties = new Properties();
        properties.load(new FileInputStream("idea_test\\src\\re.properties"));
        String classfullpath = properties.getProperty("classfullpath");
        String methodName = properties.getProperty("method");

// 加载类, 并得到 Class对象
        Class<?> cls = Class.forName(classfullpath);
// 得到 被加载的类的 一个对象实例
        Object instance = cls.getDeclaredConstructor().newInstance();
        System.out.println("instance 的运行类型为: " + instance.getClass());
// 得到 被加载的类的 方法methodName 的一个对象
// 在反射中, 可以把方法视为对象
        Method method1 = cls.getMethod(methodName);
        System.out.println("================================");
// 调用该方法
        method1.invoke(instance);

反射的优点:可以通过不修改源代码,只修改配置文件,达到控制程序的效果。

类加载器加载Cat.class字节码文件,然后在堆中就产生了一个Class对象(Class类的一个实例)(一个类只有一个Class对象),这个对象包含了Cat类的完整结构信息。(成员变量 Field[] fields,构造器 Constructor[] cons,成员方法 Method[] ms,等等)

反射相关的类

public class Cat {
    
    private String name;
    private Integer age;
    private Integer sex;

    public Cat(){
    }
    public Cat(String name){
    }
    public Cat(String name,Integer age,Integer sex){
    }
    
    public void hi(){
    
        System.out.println("hi...");
    }
    public void cry(){
    
        System.out.println("cry...");
    }
}
// 加载类, 并得到 Class对象
        Class<?> cls = Class.forName("com.itheima.Cat");
        Field[] fields = cls.getDeclaredFields();
        Method[] methods = cls.getDeclaredMethods();
        Constructor<?>[] constructors = cls.getDeclaredConstructors();

        System.out.println();
        Stream.of(fields).forEach(System.out::println);
        System.out.println("========================");
        Stream.of(methods).forEach(System.out::println);
        System.out.println("========================");
        Stream.of(constructors).forEach(System.out::println);

        // 也可以指定要取哪一个
        Field age = cls.getDeclaredField("age");
        // 得到参数为一个 String 的构造方法对象
        Constructor<?> constructor1 = cls.getDeclaredConstructor(String.class);
        // 得到无参的构造方法对象
        Constructor<?> constructor2 = cls.getDeclaredConstructor();

// Output
private java.lang.String com.itheima.Cat.name
private java.lang.Integer com.itheima.Cat.age
private java.lang.Integer com.itheima.Cat.sex
========================
public void com.itheima.Cat.hi()
public void com.itheima.Cat.cry()
========================
public com.itheima.Cat(java.lang.String,java.lang.Integer,java.lang.Integer)
public com.itheima.Cat(java.lang.String)
public com.itheima.Cat()

反射调用优化

使用反射,对执行速度有影响。

        // 传统调用方法
        m1();
        // 反射机制调用
        m2();

// Output
m1() 耗时:12
m2() 耗时:2895
    public static void m1(){
    
        Cat c = new Cat();
        long start = System.currentTimeMillis();
        for(int i = 0; i < 900000000; i++){
    
            c.hi();
        }
        long end = System.currentTimeMillis();
        System.out.println("m1() 耗时:" + (end - start));
    }
    public static void m2() throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
    
        Class<?> cls = Class.forName("com.itheima.Cat");
        Object newInstance = cls.getDeclaredConstructor().newInstance();
        Method hiMethod = cls.getMethod("hi");

        long start = System.currentTimeMillis();
        for(int i = 0; i < 900000000; i++){
    
            hiMethod.invoke(newInstance);
        }
        long end = System.currentTimeMillis();
        System.out.println("m2() 耗时:" + (end - start));
    }

Method,Field,Constructor对象都有setAccessible方法。
setAccessible作用是启动和禁用访问安全检查的开关。
设置为true,关闭检查,可以加快一点点速度。

Class类

1.Class类实例不是new出来的,而是系统进行类加载的时候创建的。
2.对于某个类的Class类实例,在内存中只有一份,因为类只加载一次。
3.通过Class类实例可以完整的得到一个类的完整结构。
4.Class类实例是存放在堆的。
5.Cat类的字节码文件二进制数据,是存放在方法区的,有的地方称为类的元数据。
一些其他的API

        Class<?> cls = Class.forName("com.itheima.Cat");

        System.out.println(cls.getName());  // 被加载的类的全限定名
        System.out.println(cls.getPackage().getName()); // 被加载的类的包名
        Field name = cls.getDeclaredField("name");
        System.out.println(name.get(instance));     // 得到属性对应的值
        name.set(instance,"xxx");                   // 设置属性的值
        System.out.println(name.get(instance));

如何得到Class类的实例?

        // 多用于配置文件, 读取类的全路径, 加载类。
        Class<?> cls1 = Class.forName("com.itheima.Cat");
        // 类名.class, 多用于参数传递。
        Class<Cat> cls2 = Cat.class;
        // 对象.getClass()
        Class<? extends Cat> cls3 = new Cat().getClass();
        // 通过类加载器[4种]
        ClassLoader classLoader = Cat.class.getClassLoader();
        Class<?> cls4 = classLoader.loadClass("com.itheima.Cat");
        // 基本数据类型(int,char,double,boolean,long,short), 按如下方式
        Class<Integer> integerClass = int.class;
        Class<Character> characterClass = char.class;
        Class<Boolean> booleanClass = boolean.class;
        // 包装类
        Class<Integer> type1 = Integer.TYPE;
        Class<Character> type2 = Character.TYPE;

哪些类型有Class类的实例?

        Class<Cat> catClass = Cat.class;    // 类,(内部类也有)
        Class<Serializable> serializableClass = Serializable.class; // 接口
        Class<Integer[]> aClass = Integer[].class;  // 数组
        Class<float[][]> aClass1 = float[][].class; // 二维数组
        Class<Deprecated> deprecatedClass = Deprecated.class;   // 注解
        Class<Thread.State> stateClass = Thread.State.class;    // 枚举
        Class<Long> longClass = long.class;     // 基本数据类型
        Class<Void> voidClass = void.class;     // void
        Class<Class> classClass = Class.class;  // Class类自身也有

深入理解Java类加载器
getDeclaredFields() 和 getFields() 区别
Class对象是放在方法区还是堆中

原网站

版权声明
本文为[Cold Snowflakes]所创,转载请带上原文链接,感谢
https://blog.csdn.net/qq_53318060/article/details/125586893