class A {
static {
System.out.println("A-SIB");
}
static void test(){
System.out.println("A-test");
}
}
class B extends A {
static {
System.out.println("B-SIB");
}
}
class C {
public static void main(String args []){
B.test();
}
}
当我运行C类时,我认为A-SIB
、B-SIB
和A-test
会被打印出来,但输出中没有B-SIB
。有人能解释一下原因吗?
以下是JLS关于类初始化的说明:
类的初始化包括执行其静态初始化器和类中声明的静态字段(类变量)的初始化器。
接口的初始化包括执行接口中声明的字段(常量)的初始化程序。
在初始化类之前,必须初始化其直接超类,但该类实现的接口不会初始化。类似地,在初始化接口之前,不会初始化接口的超接口。
类或接口类型T将在以下任何一项首次出现之前立即初始化:
- T是一个类,并且创建了T的一个实例
- T是一个类,并且调用由T声明的静态方法
- 指定了一个由T声明的静态字段
- 使用由T声明的静态字段,并且该字段不是常量变量(§4.12.4)
- T是顶级类(§7.6),执行嵌套在T(§8.1.3)中的断言语句(§14.10)
对静态字段(§8.3.1.1)的引用只会导致初始化实际声明它的类或接口,即使它可能通过子类、子接口或实现接口的类的名称来引用。
在这种情况下,在C中使用类B所做的就是调用静态方法test()
。但是这个方法是在A中声明的,而不是在B中声明的。因此,JVM不会初始化类B,因此也不会调用其静态初始化器块。
注意,类B在C的字节码中被引用,并由JVM加载。但它没有初始化。如果删除B.class
并尝试运行C,则会出现异常。
Class B
不实现(也称为"隐藏")static test
方法,因此初始执行在Class A
内开始(因此为A-SIB);然后用CCD_ 11中的CCD_。如果您在Class B
中覆盖test
,您将获得A-SIB B-SIB B-test