2012-11-20 92 views
13
 
    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”。但不是:“内部B.x”java继承的静态初始化

回答

9

的参考B.x问题下面的字节码:

getstatic  #3 <Field int B.x> 

根据Java Virtual Machine Spec

Java虚拟机指令anewarray,checkcast,getfield命令, getstatic,的instanceof,invokedynamic,invokeinterface ,invokespecial, invokestatic,invokevirtual,ldc,ldc_w,multianewarray,new, put字段,并putstatic使符号引用运行时 常量池。执行任何这些指令需要 分辨率的符号参考

所以JVM应该可以解决符号引用B.x。领域分辨率为specified like this

要在 类或C接口解析为一个场从d未解决的符号引用时,符号引用到C由场 参考给定必须首先被解析(第5.4节。 3.1)。

...

在解决一个字段引用,场分辨率首先尝试 查找的基准场C和其超

。如果C声明一个字段由 区域基准指定的名称和描述,字段查找成功。声明的字段是字段查找的结果 。

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

否则,如果C有一个超类S,场查找施加 递归到S.

否则,字段查找失败。

换句话说,JVM会将B.x分解为A.x。这就是为什么只有A类需要加载。

+0

好,但它的行为描述,我的意思是规范呢? –

+0

这不是真的。例如,您可以将静态字段'x'添加到'B',即使您不重新编译'Main',它也会被打印。 – axtavt

+0

@axtavt你是对的。我改变了一下我的答案。 – ShyJ

2

Class B延伸A它有一个public static variable x,当你调用B.x

如果你希望Inside B.作为了就把你必须创建一个类的对象,你正在访问。所有的静态代码块都被执行。或者将该静态代码块移动到类A :-)

当JVM加载类时,它会将所有静态块组合起来,并按它们声明的顺序执行它们。

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

因此,如果静态属于该类只为什么它滴落到 派生类?难道它不应该只与定义为 的类保持一致吗?

+0

是的,但为什么静态块不执行。 –

+0

您不必创建该类的对象来执行静态块。见下面 – durron597

+0

@ durron597我只是告诉一个方式来实现任何方式的问题,我的例子是为什么例子中没有执行静态代码块在派生类中:-) –

6

因为B.x实际上是A.x所以只有A类需要被加载。

2

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

public class TestMain { 
    public static void main(String[] args) { 
     System.out.println(B.x); 
     System.out.println(B.y); 
    } 

    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 B.y 

因为它不需要加载B直到东西B被访问。

Here's a good link on the subject.从文章中,“不要忘记,这些代码将在JVM加载类时执行,JVM将所有这些块组合成一个静态块,然后执行。 “

+0

所以这看起来像编译器优化,但编译器可以不同。它在某处被描述了吗? –

+0

@ user1839039:我为您添加了一个链接 – durron597

3

§12.4 "Initialization of Classes and Interfaces" of The Java Language Specification, Java SE 7 Edition规定:

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

[&hellip;]

static字段的引用(§8.3.1.1)仅使类或实际声明它接口初始化时,即使它可能通过一个子类,子接口的名称被称为或者实现接口的类。

因此,尽管—违背权利要求一些上述B —类的答案也必须加载,以确定B.xA声明,类B初始化(即它的static初始值设定项实际上没有运行),直到你做了一些更具体的B