前言
类的加载是一个重要的内容,我先简单说一说,作为明天更新Java反射机制的前置知识。反射机制是Java被称为准动态语言的一个关键原因,也就是通过反射实现类动态加载。
类加载的方式
静态加载:编译时加载相关的类
静态加载存在一些缺点:
- 对要加载的类,如果不存在就一定会报错
- 大量类的静态加载,会降低程序的启动效率
比如在启动时,包含main方法的类会被加载,然后该类中需要的类也一并加载,如果一并加载的类也存在需要加载的类,那么也要进行加载。这会大大降低程序的启动速度。利用反射进行动态加载可以解决这个问题。
动态加载:运行时加载需要的类
类会在什么时候加载?
- 创建对象的时候(同一个类只会加载一次)
- 启动的时候,包含main方法的类会被加载,然后该类中需要的类也一并加载
- 调用类中的静态成员时
- 通过发射手动加载类
类加载图解
在类的加载三大阶段 :加载、连接、初始化
加载、连接是交由JVM来进行操作,直到初始化才开始进行对程序员在类定义的静态代码块、静态变量的赋值进行操作。
加载
将编译产生字节码文件转化为二进制字节流加载到内存中去,并生成该类的Class对象(同一个类只有一个Class对象,因为相同类只加载一次)
从Java内存模型上来看
连接
a. 验证:确保字节码文件中包含的信息符合虚拟机的要求,并且不会危害虚拟机自身的安全。
验证内容:文件格式验证,元数据验证,字节码验证,符号引用验证
b.准备:由虚拟机对静态变量分配内存并且默认初始化(先对变量使用默认值初始化一遍),在JDK6以前静态变量存放与方法区在方法区分配给其的内存,JDK7之后就存放在堆中了,由堆分配内存
c: 解析:虚拟机将常量池内的符号引用替换成直接引用的过程。(在原来未加载类的时候类未分配内存,所以只是使用一个符号来表示引用,这里就将创建的地址替换对应的符号)
初始化
执行()方法,该方法按从上往下的顺序,依次收集类中的所有静态代码中的语句以及静态变量的赋值进行合并,虚拟机会保证在加载一个类时的()方法在多线程时进行加锁操作,使方法同步