java继承的静态初始化
public class Main { public static void main(String[] args) { System.out.println(B.x); } } class A { public static String x = "x"; } class B extends A { static { System.out.print("Inside B."); } }
问题:为什么输出将是:“x”。 但不是:“内部Bx”
对Bx
的引用发出以下字节码:
getstatic #3 <Field int B.x>
根据Java虚拟机规格
Java虚拟机指令anewarray,checkcast,getfield命令,getstatic,的instanceof,invokedynamic,invokeinterface,invokespecial,invokestatic,invokevirtual,最不发达国家,ldc_w,multianewarray,新,putfield,并putstatic做出运行时间常量池中的符号引用 。 执行任何这些指令都需要解析其符号引用 。
所以JVM应该解析对Bx
的符号引用 。 现场分辨率是这样指定的:
要解析从D到类或接口C中字段的未解析符号引用,必须首先解析由字段引用给出的对C的符号引用(第5.4.3.1节)。
...
解析字段引用时,字段解析首先尝试查找C及其超类中的引用字段:
如果C使用由字段引用指定的名称和描述符声明一个字段,则字段查找将成功。 声明的字段是字段查找的结果。
否则,字段查找将递归应用于指定类或接口C的直接超级接口。
否则,如果C具有超类S,则字段查找将递归应用于S.
否则,字段查找失败。
换句话说,JVM会将Bx
解析为Ax
。 这就是为什么只有A
类需要加载。
因为Bx
实际上是Ax
所以只需要加载A
类。
Java SE 7版的Java语言规范的§12.4“类和接口的初始化”指定:
类的初始化包括执行其static
初始化程序以及在类中声明的静态字段(类变量)的初始化程序。
[...]
对static
字段(第8.3.1.1节)的引用只会初始化实际声明它的类或接口,即使它可能通过子类名称,子接口或实现接口的类来引用。
因此,尽管-违背了上面的一些答案的说法-类B
确实有被加载,以确定Bx
是声明在A
,类B
未初始化(即,它的static
初始化没有实际运行),直到你做一些更具体的B