1、主动使用 与 被动使用 的定义
主动使用 的7种情况:
- 创建类的实例对象,如
new Person()
; - 访问 (包括接口、抽像类)的静态变量,或者对其 赋值;
- 调用类的静态方法;
- 使用 反射
Class.forName("com.test.Test")
,对类进行反射调用的时,如果类没进行初始化,需要先调用其初始化方法进行初始化。 - 当初始化一个类时,如果其父类还未进行初始化,会先触发其父类的初始化。
- 虚拟机启动时,被指定一个要执行的主类( 包含main()方法的类 ),虚拟机会先初始化这个类。
- 当使用JDK7 等动态语言支持时,如果一个
java.lang.invoke.MethodHandle
实例最后的解析结果REF_getStatic
、REF_putStatic
、REF_invokeStatic
的方法句柄,并且这个方法句柄所对应的类没有进行过初始化,则需要先触发其初始化。
《虚拟机规范》中使用的限定词是 “有且仅有”
,因此,除上面的7种情况,其他使用类的方式都被看作是 类的 被动使用 。
2、主动使用 和 被动使用 的区别 ?
主动使用:执行加载、连接、初始化
被动使用:执行加载、连接, 但是不执行类的初始化,不会执行JVM中的 clinit()
,即不会 对 静态变量 的初始化 和 静态代码块 的赋值。
JVM类加载的过程(类加载子系统) : https://xiaojin21cen.blog.csdn.net/article/details/79480012
3、Java类的初始化规则
- 类按静态变量、静态代码块的 定义顺序 初始化 。
- 先初始化父类 ;
- 当访问一个Java类或接口中的静态域的时候,只有真正声明这个域的类或接口才会被初始化。
- 接口初始化不会导致父接口的初始化。
示例:
class Parent {
public static int age = 36;
static {
System.out.println("Class Parent is initialized");
}
}
class Child extends Parent {
public static int number = 3;
static {
System.out.println("Class Child is initialized");
}
}
public class Test7 {
static {
System.out.println("Class Test7 is initialized");
}
public static void main(String[] args) {
int age = Child.age;
}
}
运行结果:
Class Test7 is initialized
Class Parent is initialized
说明:
Child.age 引用了其父类 Parent 中声明的静态变量 age ,根据初始化规则第三条,由于 age 是在父类 Parent 中声明定义的 ,所以只加载初始化父类 Parent ,不初始化 Child 。
4、 示例
相关文章: