反射机制
将类的各个组成部分封装成其他对象。
比如现在有一个Person类(Person.java),有1个成员变量name和age,有1个构造函数,和一个成员方法eat()。经过javac编译后,生成Person.class字节码文件。当我们想使用Person类时,需要将Person.class加载到内存中(这里边有一个类加载机制),每个Person.class的字节码文件加载到内存中都会封装成Class对象形式存储,Class对象里由成员变量对象(Field类),构造方法对象(Constructor类)和成员方法类(Method类)组成,也就是Person类中的成员变量、构造方法和成员方法被加载到内存中被封装成了Field对象,Constructor对象和Method对象,并且以数组的形式存储。这个封装的过程就是反射机制。
· 好处:
-
可以在程序运行过程中操作这些对象。比如在IDEA中,我们想使用某个对象的方法或者变量时,IDEA会给出相应的提示,这就是一个反射机制的例子。
-
可以解耦,提高程序的可扩展性
1 获取Class对象的方式
-
Class.forName("全类名"):将字节码文件加载至内存,返回Class对象
-
这种方式可以得到还未加载至内存的Class对象,多用于配置文件中,将类名定义在配置文件中,读取文件后加载类,如在JDBC中创建jdbc.properties文件,读取文件中的数据库驱动(如com.mysql.jdbc.Driver),然后Class.forName("com.mysql.jdbc.Driver")加载Drive类。
-
-
类名.class:通过类名的属性class获取
-
多用于参数传递
-
-
对象.getClass():*getClass()方法在Object*类中定义
-
多用于对象获取字节码
-
public void reflect1() throws ClassNotFoundException {
//方式一:Class.forName("全类名");
Class cls1 = Class.forName("com.test.domain.Person"); //Person自定义实体类
System.out.println("cls1 = " + cls1);
//方式二:类名.class
Class cls2 = Person.class;
System.out.println("cls2 = " + cls2);
//方式三:对象.getClass();
Person person = new Person();
Class cls3 = person.getClass();
System.out.println("cls3 = " + cls3);
// == 比较三个对象
System.out.println("cls1 == cls2 : " + (cls1 == cls2)); //true
System.out.println("cls1 == cls3 : " + (cls1 == cls3)); //true
System.out.println("cls2 == cls3 : " + (cls2 == cls3)); //true
//结论:同一个字节码文件(*.class)在一次程序运行过程中,只会被加载一次,无论通过哪一种方式获取的Class对象都是同一个。
}
输出:
cls1 = com.test.domain.Person
cls2 = com.test.domain.Person
cls3 = com.test.domain.Person
cls1 == cls2 : true
cls1 == cls3 : true
cls2 == cls3 : true
同一个字节码文件(*.class)在一次运行过程中,只会被加载一次,即使用以上三种方式获取的同一个类的Class对象都是同一个。
Class对象的使用参考:https://note.youdao.com/ynoteshare1/index.html?id=128508bf6a04968eced81ede9ac1b304&type=note