不为派生类调用静态初始值设定项

Ser*_*aev 11 java

以下Java代码不会调用类的静态初始化程序B.为什么?

码:

class A 
{
    static 
    {
        System.out.println("A static init");
    }

    public static void f() 
    {
        System.out.println("f() called");
    }
}

class B extends A 
{
    static 
    {
        System.out.println("B static init");
    }
}

public class App
{
    public static void main( String[] args)
    {
        B.f(); //invokestatic  #16                 // Method com/db/test/B.f:()V
    }
}
Run Code Online (Sandbox Code Playgroud)

节目输出:

A static init
f() called
Run Code Online (Sandbox Code Playgroud)

在JDK 1.8.0_25上测试过

Era*_*ran 13

没有"静态构造函数"这样的东西.它是一个静态初始化块,只在初始化类时执行.由于您正在调用类A的静态方法(即使您通过类B引用它),因此无需初始化类B.调用B.f();与调用相同A.f();.

如果创建类B的实例或访问类B的静态成员/方法,则将执行类B的静态初始化块.

以下是触发类初始化的唯一条件(JLS 12.4.1):

类或接口类型T将在第一次出现以下任何一个之前立即初始化:

 T is a class and an instance of T is created.

 T is a class and a static method declared by T is invoked.

 A static field declared by T is assigned.

 A static field declared by T is used and the field is not a constant variable (§4.12.4).

 T is a top level class (§7.6), and an assert statement (§14.10) lexically nested within T (§8.1.3) is executed.
Run Code Online (Sandbox Code Playgroud)


The*_*ind 5

由于只有类A定义了方法f(,所以类B加载但未初始化.

你可以java -verbose:class MyClassName用来检查这个.

在jdk6/jdk 8机器上,将打印.

[Loaded App from file:/C:/XXXX/]
[Loaded A from file:/C:/XXXXXX]
[Loaded B from file://C:/XXXXXXX]
A static init
f() called
Run Code Online (Sandbox Code Playgroud)

B将被懒惰初始化但是贪婪加载(因为它被引用).

将您的代码更改为A.f().然后你会看到B没有加载.

[Loaded App from file:/C:/XXXX/]
[Loaded A from file:/C:/XXXXX]
A static init
f() called
Run Code Online (Sandbox Code Playgroud)

注意:类加载初始化是两回事.检查文档以Class.forName()获取详细信息.