赞
踩
上图加载 验证 准备 初始化 卸载 这5个阶段是俺按部就班开始的,不是执行完一个再执行一个,而是这些阶段互相交叉地混合进行.解析可以在初始化完成之后.
上述六中场景会触发类的初始化,这六种场景中的行为称为主动引用,其余方式的称为被动引用.
public class SupperClass { static{ System.out.println("SuperClass init"); } public static int value=123; } public class SubClass extends SupperClass { static{ System.out.println("SubClass init"); } public class NotInitialization { /** * 子引用父类静态字段,不会初始化子类 */ @Test public void test1(){ System.out.println(SubClass.value); } }
SuperClass init
123
System.out.println(SubClass.value);
输出为:
SuperClass init
123
但理论上被final修饰后,已经在编译器将结果放入常量池中了, why还是会初始化?
System.out.println(SupperClass.value);
输出为:123
解释:编译阶段已经将123存入常量池中了,该类对常量的引用被转化为对自身常量池的引用.
5. 继承关系图
加载过程将虚拟机外部的字节码文件(二进制字节流文件)存储在方法区之中,具体过程如下
验证的目的是class文键字节流包含的信息符合 <<虚拟机规范>>的全部约束要求,保证这些代码运行后不会危害虚拟机自身安全.主要包括 文件格式验证,元数据验证,字节码验证,福海引用验证.
准备阶段正式为类中定义的变量(static)分配内存并赋初始值
这些变量所拥有的内存在JDK7以前存在方法区(永久代实现),但JDK7以后,类变量会随着class对象存放在java堆中分配完内存会赋初始值(零值).实例变量将会在对象实例化时随对象一起分配在java堆中.当类字段的字段属性表中存在ConstantValue属性时,==在准备阶段直接将 final static 的值设置为该属性的属性值(直接初始化)==其它情况的类变量的初始化发生在类的初始化阶段
package chpter7.T7_4; /** * @ClassName FieldResolution * @Description TODO * @Author 86134 * @Date 2022/8/31 17:54 * @Version 1.0 **/ public class FieldResolution { interface interface0{ int A=0; } interface interface1 extends interface0{ int A=1; } interface interface2{ int A=2; } static class Parent implements interface1{ public static int A=3; } static class Sub extends Parent implements interface2{ // public static int A=4; } public static void main(String[] args) { System.out.println(Sub.A); } } 输出: Error:(30, 31) java: 对A的引用不明确 chpter7.T7_4.FieldResolution.Parent 中的变量 A 和 chpter7.T7_4.FieldResolution.interface2 中的变量 A 都匹配
初始化阶段会初始化类变量和其它资源.本质上,初始化阶段就是执行类构造器<clinit>()方法的过程.
<clinit>()由javac编译器自动生成. <clinit>()是由编译器收集类中的所有类变量赋值动作和静态语句块(static{}) 中的语句合并产生的,编译器收集的顺序是由源文件中语句出现的顺序决定的静态语句块只能==访问(不是赋值)==到定义到它之前的变量,如果访问它之后的变量,编译器会提示"非法的前向访问"(因为静态变量还没有初始化,不能访问).因为在准备阶段静态已经为静态变量分配空间并赋零值,所有可以在静态代码块中为它之后定义的变量赋值.例如
public class Test { static { i=1; } static int i ; public static void main(String[] args) { System.out.println(i); } } 输出:1 //static 修饰的变量其实不用初始化系统也不会报错,因为有赋 //零值的过程,但成员变量不行(錯誤) public class Test02 { public int i; public static void main(String[] args) { System.out.println(new Test02().i); } 成員變量也可以
public class Parent { public static int A=1; static { A=2; } } public class Sub extends Parent { public static int B=A; public static void main(String[] args) { System.out.println(Sub.B); } } // 输出 2
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。