类加载
我们知道,Java文件被编译成 .class 文件,然后被加载到JVM内存中(如果对JVM内存了解,就会发现是方法区)。之后进行验证、准备、解析、初始化,然后就可以被使用了。当然,不在需要的时候,也可以将类从内存中卸载。
其实在加载阶段,JVM需要完成以下三件事情:
1. 通过一个类的全限定名来获取其定义的二进制字节流。(一般是根据类名)
2. 将这个字节流所代表的静态存储结构转化为方法区的运行时数据结构。
3. 在 Java 堆中生成一个代表这个类的 java.lang.Class 对象,作为对方法区中这些数据的访问入口。
此时类的Class数据就在方法区中了,且每个类只有一份。另外唯一一个该类的Class对象在堆中。
public class HelloWold {
public static void main(String[] args) {
System.out.println(HelloWold.class instanceof Class);// true
System.out.println(HelloWold.class.hashCode());// 1
HelloWold hw = new HelloWold();
HelloWold hw2 = new HelloWold();
System.out.println(hw.getClass().hashCode());// 2
System.out.println(hw2.getClass().hashCode());// 3
}
}
运行代码,就会发现1,2,3 三个地方输出的值是一样的。
Class
Class类其实也是一个类,只不过比较特殊。特殊在这是一个在类加载过程中由虚拟机生成的,表示被加载类的类型信息的对象。比如: HelloWold hw = new HelloWold();怎么知道 hw 的类型是 HelloWold呢?就是通过这个Class类知道的。
而且Class里面存储了对应类的几乎所有的信息,当然这些信息是未初始化的信息,比如所有的方法,所有的构造函数,所有的字段(成员属性)等等。Java 反射的前提就是获取Class对象。
打开源码就会发现,Class 类只有私有构造,而且是final的。
private Class(ClassLoader loader) {
// Initialize final field for classLoader. The initialization va