Статический инициализатор не вызывается для производного класса

Следующий код 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
    }
}

Выход программы:

A static init
f() called

Протестировано на JDK 1.8.0_25

Ответ 1

Нет такой вещи, как "статический конструктор". Это статический блок инициализации, и он выполняется только при инициализации класса. Поскольку вы вызываете статический метод класса 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.

Ответ 2

Поскольку только класс 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

Класс B будет инициализирован лениво, но загружен жадно (поскольку он передается).

Измените код на A.f(). Затем вы увидите, что B не загружен.

[Loaded App from file:/C:/XXXX/]
[Loaded A from file:/C:/XXXXX]
A static init
f() called

Примечание. Загрузка и инициализация классов - это две разные вещи. Подробнее см. Документацию Class.forName().