类型装载
装载阶段由三个基本动作组成:
1)根据类型的完全限定名,产生一个能够代表该类型的二进制流
2)解析这个二进制流为方法区的数据结构
3)创建一个能够代表该类型的java.lang.Class实例
实际上就是一个把二进制数据流解析为方法区的数据结构,并在堆中创建一个实例,这就是装载。
java类型的装载要么由启动类装载器装载,要么由用户自定义的类装载器装载。
连接
验证
连接的第一步是验证----确认类型符合java语言的语义,并且不会危机虚拟机的完整性。
在验证阶段,虚拟机规范列出了虚拟机可以抛出异常及在何种条件下必须抛出他们。
在装载阶段的解析二进制流和构造方法区的数据结构时,虚拟机必须对一些特定的验证,确保二进制数据不会导致虚拟机崩溃。
另一个装载阶段需要验证的是,确保除了Object类之外都必须有一个超类。
虽然属于装载阶段,但也进行了验证。
在验证阶段所做的事:
首先需要确保各个类之间的二进制兼容。
1.检查final类不能拥有子类
2.检查final类不能被覆盖
3.确保子类与超类之间没有不兼容的方法声明
上述检查需要查看其他类型,只需要查询超类。所以超类需要在子类之前初始化。然而对于实现了父接口的子类初始化时,父接口必须装载,然而不会被初始化。
4.检查所有常量池入口相互之间是否一致
5.检查常量池中的所有特殊字符
6.检查字节码的完整性
准备
虚拟机执行了一些它选择的验证后,类就进入了准备阶段。在准备阶段,java虚拟机为类变量分配内存,设置默认初始值。
解析
解析过程就是在类型的常量池中寻找类、接口、字段和方法的符号引用,并把这些符号引用替换成引用的过程。
初始化
在java代码中一个正确的初始值是通过类变量初始化语句或者静态初始化语句给出的。
初始化一个类包含两个步骤:
1.如果类存在超类,且超类还没有被初始化,则先初始化超类
2.如果类存在一个初始化方法则执行该方法。否则执行默认的。
主动使用和被动使用
当使用一个非常量的静态字段时,只有这个字段是被当前类或接口声明的情况才是主动使用
如果是子接口和实现了该接口的类使用此接口中的字段都会被认为是被动使用,不会引发初始化。