java继承的静态初始化

时间:2012-11-20 14:19:17

标签: java inheritance static static-initialization

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。但不是:Inside B.x

5 个答案:

答案 0 :(得分:10)

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,   putfield和putstatic将符号引用添加到运行时   恒定的池。执行任何这些指令都需要   解析其符号引用

因此JVM应该解析符号引用B.x 。字段分辨率为specified like this

  

将未解析的符号引用从D解析为a中的字段   class或interface C,字段给出的对C的符号引用   必须首先解决参考(第5.4.3.1节)。

     

...

     

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

     

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

     

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

     

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

     

否则,字段查找失败。

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

答案 1 :(得分:7)

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

答案 2 :(得分:4)

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

  

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

     

[...]

     

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

所以尽管 - 与上面某些答案中的声明相反 - 类B确实必须加载,以确定B.x在{{}中声明1}},类A不是初始化(即,它的B初始化程序实际上并未运行),直到您执行更具体的static

答案 3 :(得分:2)

Class B扩展A,当您拨打public static variable x

时,您正在访问B.x

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

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

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

  

因此,如果Static属于Class,那么为什么它会逐渐减少       派生类?它不应该只停留在它所在的类       定义了吗?

答案 4 :(得分: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.从文章&#34;并且不要忘记,当JVM加载类时,将执行此代码。 JVM将所有这些块组合成一个静态块然后执行。以下是我要提及的几点:&#34;