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

回答(5)

2 years ago

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应该解决 symbolic reference to B.x . 字段分辨率为specified like this

要将未解析的符号引用从D解析为类或接口C中的字段,必须首先解析由字段引用给出的对C的符号引用(第5.4.3.1节) . ...在解析字段引用时,字段解析首先尝试在C及其超类中查找引用字段:如果C声明具有字段引用指定的名称和描述符的字段,则字段查找成功 . 声明的字段是字段查找的结果 . 否则,将字段查找递归地应用于指定类或接口C的直接超接口 . 否则,如果C具有超类S,则将字段查找递归地应用于S.否则,字段查找失败 .

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

2 years ago

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

2 years ago

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

类的初始化包括执行其静态初始化程序和类中声明的静态字段(类变量)的初始化程序 . [...]对静态字段的引用(第8.3.1.1节)仅导致实际声明它的类或接口的初始化,即使它可能通过子类的名称,子接口或实现的类来引用一个界面 .

所以尽管 - 与上面某些答案中的声明相反 - 类 B 确实必须加载,为了确定 B.xA 中声明,类 B 未初始化(即,它的 static 初始化器实际上没有运行),直到你做一些更具体的事情 B .

2 years ago

它实际上不需要加载 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.来自文章,"And dont forget, this code will be executed when JVM loads the class. JVM combines all these blocks into one single static block and then executes. Here are a couple of points I like to mention: "

2 years ago

Class B 扩展 A ,当您拨打 B.x 时,您正在访问 public static variable x

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

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

EDITSource):简短的回答是静态不是在Java中继承的 . 相反,在类中声明的静态成员(受限于"access"限制)在派生类的名称空间中直接可见,除非它们在派生类中通过声明"hidden" .

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