Java的反射机制是在运行过程中,对于任何一个类,都能够知道这个类的所有属性和方法;对于任何一个对象,都能够调用他的任何一个方法和属性(这种说法不正确,我之前调用private方法时就报错。必须要在前面设置一下权限才能使用)。这种动态获取的信息以及动态调用对象的功能称为java语言的反射机制。
我们知道,在java语言中,我们可以获取一个对象的类型(对象.getClass()),也可以获取一个类的类名(类.class),也可以使用.forName(类名)。那么这三种方法一样嘛?
我们用下面这段程序作为验证,来看前面getClass()方法和.class属性有何区别:
返回结果是:
看来结果是一样的。那我们再来看看两者其中的过程:
Student类如图:
但无论怎么改变main函数中三个反射方法的顺序,输出结果如下:
当然了,我们已经验证过在main函数中输出的这三者内容相同,因此我就省略了那些个输出,只留下了Student类当中写的输出方法。
然后我又进行了多次尝试。经过试验表明,直接用Student.class,不会启动构造函数、静态参数初始化、动态参数初始化,用forName只会启动静态函数初始化,用getClass因为要创建实例,显然三者都是要启动的。
而我们知道,类的生命周期分为装载、链接、初始化、使用、卸载五部分,静态代码的初始化发生在类的初始化阶段,动态代码的初始化发生在类的使用阶段(也就是类的实例化)。通过上面结果,我们就可以知道,.class的初始化发生在类的初始化之前,forName发生在类的初始化阶段,而.getClass初始化则发生在类的使用阶段。(这一段措辞可能不太准确,了解我想表达的意思就行了)
后面两者容易理解,那么我们来了解一下.class究竟发生在类的生命周期的哪一步。
1、当我们new一个新对象的时候,jvm会加载women的student.class。
2、然后jvm会去我们本地磁盘找student.class文件,并加载到jvm内存中。
3、在将.class文件读入内存之后,jvm会自动创建一个class对象,这其中包括了.class、.fields等等属性,该过程有且只有一次。这一步完成是在类的加载阶段,而不是只有在(1)中new一个对象的时候。只要在程序中第一次加载该类的时候,就会完成这个操作。