类的加载机制
运行期类加载。即在语言里面,类型的加载、连接和初始化过程都是在程序运行期完成的,从而通过牺牲一些性能开销来换取Java程序的高度灵活性
什么是运行期,什么是编译期?
编译期是指编译器将源代码翻译为机器能识别的代码,Java被编译为Jvm认识的**字节码文件,运行期 则是指Java代码的 运行 过程。
JVM运行期 动态加载 + 动态连接 -> Java的动态扩展特性
类加载的生命周期:
1.加载
-
加载阶段虚拟机完成的事:
- 通过类的全限定名来获取定义此类的二进制字节流。
- 将该二进制字节流所代表的静态存储结构转化为方法区的运行时数据结构,该数据存储数据结构由虚拟机实现自行定义
- 在内存中生成一个代表这个类的java.lang.Class对象,它将作为程序访问方法区中的这些类型数据的外部接口
注:数组类不通过类加载器创建而是由虚拟机直接创建的,但是数组类的元素类型需要靠类加载器去创建
2.连接
-
验证:为了确保Class文件的字节流中包含的信息符合虚拟机的要求,并且不会危害虚拟机安全。验证到不符合Class文件格式约束的字节流,会抛出java.lang.VerifyError异常或其子类异常。由于验证不一定必要所以通过
-Xverify:none
关闭验证。- 文件格式验证
- 验证字节流是否符合Class文件格式的规范,以及能否被当前的虚拟机处理。
- 保证输入的字节流能正确的解析并存储在方法区中,且格式上符合一个java类型信息的要求。
- 只有保证二进制字节流通过了该验证后,她才会进入内存的方法区中进行存储,所以后续3个验证阶段全部是基于方法区而不是字节流了。
- 元数据验证
- 对字节码描述的信息进行语义分析,以保证其描述的信息符合Java语言规范的要求。
- 对类的元数据进行语义校验,保证不存在不符合Java语言规范的元数据信息。
- 字节码验证
- 是验证过程中最复杂的一个阶段
- 对类的方法体进行校验分析,保证被校验类的方法在运行时不会做出危害虚拟机安全的事件
- 通过数据流和控制流分析,确定要程序语义是合法的,符合逻辑的。
- 符号引用验证
- 对类信息自身以外的信息进行匹配性校验,
- 确保解析动作能正常执行,如果无法通过符号引用验证,那么将会抛出一java.lang.IncompatibleClassChangeError异常的子类
- 注意:该验证发生在虚拟机将符号引用转化为直接引用的时候,即『解析』阶段
- 文件格式验证
-
准备
- 一个Class文件的字节流通过验证,就开始为该对象的类变量,也就是静态变量,分配内存和初始值,这些变量使用的内存都在方法区中进行分配。
各种数据类型的初始值:
值得注意的是:
final修饰的变量:
private static int aa = 10;