Статический инициализатор не вызывается для производного класса
Следующий код 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()
.