java虚拟机规定必须立即初始化类的5种情况
2017-08-09 14:06
169 查看
Java类加载机制中,规定了有且仅有5种情况必须立即对类进行初始化(而加载,验证,准备自然再次之前):
1. 遇到new,getstatic,putstatic和invokestatic这4条指令时,如果类没有初始化时,必须初始化类。四条指令对应我们日常所见的 使用new关键字实例化对象,读取一个类的静态字段,设置一个类的静态字段(被final修饰的静态字段除外,因为已在编译期把结果放入常量池中了)和调用一个类的静态方法。
2. 对类进行反射调用时。
3. 当初始化一个子类时,发现其父类没有初始化,则需先出发其父类的初始化。
4. 当虚拟机启动时,一个类包含main()方法时,当前类需要初始化
5. 但是用动态语言支持时,如果一个java.lang.invoke.MethodHandle实例后解析结果REF_putStatic,REF_getStatic,REF_invokeStatic的方法句柄时,当改方法句柄对应的类没有初始化时,需要初始化该类。(动态语言支持详情请查看)
初次之外所有引用类的地方都不会出发类初始化,被称为被动应用,下面举三个例子:
1. 通过子类应用父类静态字段,不会导致子类初始化,代码如下:
结果:
SuperClass Init !!!
123
结果只输出了”SuperClass Init !!!”, “SubClass Init !!!”没有出来,对应静态字段,只有直接定义改字段的类才会初始化。
2 .通过数组定义来引用类,不会出发此类的初始化,代码如下:
运行结果并没有打印出”SuperClass Init !!!”,这里并没有出发com.sun.jojo.noinitclass.SuperClass类的初始化.这里触发了另一个名为“[Lcom.sun.jojo.noinitclass.SuperClass”的类的初始化,他是虚拟机自动创建的,直接继承于java.lang.Object的子类,创建动作由字节码指令newarray触发。
3.常量在编译期间就会调入类的常量池中,本质上没有直接引用的定义变量的类,因此使用常量字段时不会触发累的初始化。
结果:只打印出123 “ConstClass Init !!!”并没有打印出来。
接口的初始化和类的初始化类似,区别在于5种中的第三种:当一个子类的初始化过程中需要去报其父类也必须先初始化,但接口初始化时不要求其父接口也进行初始化,只有在用到父接口时,才去初始化。
1. 遇到new,getstatic,putstatic和invokestatic这4条指令时,如果类没有初始化时,必须初始化类。四条指令对应我们日常所见的 使用new关键字实例化对象,读取一个类的静态字段,设置一个类的静态字段(被final修饰的静态字段除外,因为已在编译期把结果放入常量池中了)和调用一个类的静态方法。
2. 对类进行反射调用时。
3. 当初始化一个子类时,发现其父类没有初始化,则需先出发其父类的初始化。
4. 当虚拟机启动时,一个类包含main()方法时,当前类需要初始化
5. 但是用动态语言支持时,如果一个java.lang.invoke.MethodHandle实例后解析结果REF_putStatic,REF_getStatic,REF_invokeStatic的方法句柄时,当改方法句柄对应的类没有初始化时,需要初始化该类。(动态语言支持详情请查看)
初次之外所有引用类的地方都不会出发类初始化,被称为被动应用,下面举三个例子:
1. 通过子类应用父类静态字段,不会导致子类初始化,代码如下:
package com.sun.jojo.noinitclass; public class SuperClass { static { System.out.println("SuperClass Init !!!"); } public static int value = 123; } package com.sun.jojo.noinitclass; public class SubClass extends SuperClass{ static { System.out.println("SubClass Init !!!"); } } package com.sun.jojo.noinitclass; public class NotInitialization { public static void main(String[] args) { System.out.println(SubClass.value); } }
结果:
SuperClass Init !!!
123
结果只输出了”SuperClass Init !!!”, “SubClass Init !!!”没有出来,对应静态字段,只有直接定义改字段的类才会初始化。
2 .通过数组定义来引用类,不会出发此类的初始化,代码如下:
package com.sun.jojo.noinitclass; public class NotInitialization { public static void main(String[] args) { //System.out.println(SubClass.value); SuperClass[] superClasses = new SuperClass[10]; } }
运行结果并没有打印出”SuperClass Init !!!”,这里并没有出发com.sun.jojo.noinitclass.SuperClass类的初始化.这里触发了另一个名为“[Lcom.sun.jojo.noinitclass.SuperClass”的类的初始化,他是虚拟机自动创建的,直接继承于java.lang.Object的子类,创建动作由字节码指令newarray触发。
3.常量在编译期间就会调入类的常量池中,本质上没有直接引用的定义变量的类,因此使用常量字段时不会触发累的初始化。
public class ConstClass { static { System.out.println("ConstClass Init !!!"); } public static final int value = 123; } public class NotInitialization { public static void main(String[] args) { //System.out.println(SubClass.value); //SuperClass[] superClasses = new SuperClass[10]; System.out.println(ConstClass.value); } }
结果:只打印出123 “ConstClass Init !!!”并没有打印出来。
接口的初始化和类的初始化类似,区别在于5种中的第三种:当一个子类的初始化过程中需要去报其父类也必须先初始化,但接口初始化时不要求其父接口也进行初始化,只有在用到父接口时,才去初始化。
相关文章推荐
- 【Java基础知识】Java虚拟机需立即初始化类的5种情况
- 四种情况下必须立即对类进行“初始化”
- c++中必须用初始化列表初始化的情况
- 三种情况必须在类构造函数初始化列表初始化
- 必须在初始化列表中初始化的---4种情况
- 必须用到初始化成员列表的四种情况
- 必须要使用成员初始化列表的情况
- 四种必须用到初始化成员列表的情况
- c++构造函数必须用到初始化成员列表的四种情况
- 必须使用【初始化列表】初始化数据成员的情况
- 必须采用初始化列表一共有三种情况
- 【c++】必须在类的初始化列表中初始化的的几种情况
- c++必须在类初始化列表中初始化的几种情况??
- C++必须使用【初始化列表】初始化数据成员的三种情况
- C++:四种必须使用初始化列表情况
- c++中必须在类初始化列表中初始化的几种情况
- 【c++】必须在类初始化列表中初始化的几种情况
- 【c++】必须在类初始化列表中初始化的几种情况
- 什么情况下必须使用C++的初始化列表
- 必须在初始化列表中的情况