javainheritance的静态初始化

public class Main { public static void main(String[] args) { System.out.println(Bx); } } class A { public static String x = "x"; } class B extends A { static { System.out.print("Inside B."); } } 

问题:为什么输出将是: x 。 但不是: Inside Bx

Bx的引用会发出以下字节码:

 getstatic #3  

根据Java虚拟机规范

Java虚拟机指示anewarray,checkcast,getfield, getstatic ,instanceof,invokedynamic,invokeinterface,invokespecial,invokestatic,invokevirtual,ldc,ldc_w,multianewarray,new,putfield和putstatic对运行时常量池进行符号引用 。 执行任何这些指令都需要解析其符号引用

因此JVM应该解析Bx符号引用 。 字段分辨率指定如下 :

要解决从D到类或接口C中的字段的未解析的符号引用,必须首先解析由字段引用给出的对C的符号引用(第5.4.3.1节)。

解析字段引用时,字段解析首先尝试在C及其超类中查找引用的字段:

如果C声明具有字段引用指定的名称和描述符的字段,则字段查找成功。 声明的字段是字段查找的结果。

否则,将字段查找递归地应用于指定类或接口C的直接超接口。

否则,如果C具有超类S,则将字段查找递归地应用于S.

否则,字段查找失败。

换句话说,JVM会将Bx解析为Ax 。 这就是为什么只需要加载A类的原因。

因为Bx实际上是Ax所以只需要加载A类。

§12.4JavaSE 7 规范Java语言规范的 “类和接口的初始化”指定:

类的初始化包括执行其static初始化程序和类中声明的静态字段(类变量)的初始化程序。

[…]

static字段的引用(第8.3.1.1节 )仅导致实际声明它的类或接口的初始化,即使它可能通过子类的名称,子接口或实现接口的类来引用。

因此,尽管 – 与上述某些答案中的声明相反 – 必须加载 B类,为了确定BxA声明, B类未初始化 (即,其static初始化器实际上并未运行),直到您做一些比B更具体的事情。

它实际上不需要加载B直到它直接访问B的静态成员。 注意这段代码:

 public class TestMain { public static void main(String[] args) { System.out.println(Bx); System.out.println(By); } static class A { public static String x = "x"; } static class B extends A { public static String y = "y"; static { System.out.print("Inside B."); } } } 

将输出:

 x Inside By 

因为在访问B某些内容之前不需要加载B

这是关于这个主题的一个很好的链接。 从文章“不要忘记,这个代码将在JVM加载类时执行.JVM将所有这些块组合成一个静态块然后执行。这里有几点我想提一下:”

Class B扩展A ,它有一个public static variable x ,当你调用Bx时,它正在访问

如果你期望Inside B. as out,你必须创建该类的Object。 执行所有静态代码块。 或将该静态代码块移动到A类:-)

当JVM加载类时,它会对所有静态块进行分组,并按照它们声明的顺序执行它们。

编辑来源 ):简短的回答是静态不是用Javainheritance的。 相反,在类中声明的静态成员(受“访问”限制)在派生类的名称空间中直接可见,除非它们在派生类中被声明“隐藏”。

因此,如果静态属于类,那么为什么它会逐渐渗透到派生类? 它不应该只停留在定义它的类中吗?