Поведение статических блоков с наследованием
Я пытаюсь использовать статические блоки следующим образом:
У меня есть базовый класс Base.java
public class Base {
static public int myVar;
}
И производный класс Derived.java
:
public class Derived extends Base {
static
{
Base.myVar = 10;
}
}
Моя функция main
такова:
public static void main(String[] args) {
System.out.println(Derived.myVar);
System.out.println(Base.myVar);
}
Это печатает вывод out как 0 0
, где я ожидал 10 0
. Может ли кто-нибудь объяснить это поведение? Кроме того, если я хочу, чтобы мои производные классы устанавливали значения для статической переменной, как я могу это достичь?
Ответы
Ответ 1
Как я понимаю. Вы не называете какие-либо свойства Derived
(myVar
принадлежит Base
, а не Derived
). И java не запускает статический блок из Derived
. Если вы добавите статическое поле в Derived
и получите к нему доступ, тогда java выполнит все статические блоки.
class Base {
static public int myVar;
}
class Derived extends Base {
static public int myVar2;
static
{
Base.myVar = 10;
}
}
public class Main {
public static void main( String[] args ) throws Exception {
System.out.println(Derived.myVar2);
System.out.println(Base.myVar);
}
}
Из спецификации java, когда класс инициализируется (и статический блок был выполнен):
12.4.1 При возникновении инициализации Класс или тип интерфейса T будет инициализирован непосредственно перед первым вхождением любого из следующих значений:
• T - класс, и создается экземпляр T.
• T - класс, и статический метод, объявленный T, вызывается.
• Назначено статическое поле, объявленное T.
• Используется статическое поле, объявленное T, и поле не является постоянной переменной (§4.12.4).
• T - класс верхнего уровня (§7.6), и выполняется утверждение (§14.10), лексически вложенное в T (§8.1.3).
Ответ 2
Статические блоки инициализатора не запускаются до тех пор, пока класс не будет инициализирован. См. Спецификация языка Java, пункты 8.7 (Статические инициализаторы) и 12.4.1 (При инициализации):
Статический инициализатор, объявленный в классе, выполняется, когда класс инициализировано (§12.4.2). Вместе с любыми инициализаторами полей для класса переменные (§8.3.2), статические инициализаторы могут использоваться для инициализации класс переменных класса.
Здесь аналогичный пример из JLS 12.4.1:
class Super {
static int taxi = 1729;
}
class Sub extends Super {
static { System.out.print("Sub "); }
}
class Test {
public static void main(String[] args) {
System.out.println(Sub.taxi);
}
}
Эта программа печатает только:
1729
потому что класс Sub никогда не инициализируется; ссылка на Sub.taxi является ссылкой на поле, фактически объявленное в классе Super, и делает не запускать инициализацию класса Sub.
Ответ 3
Существует одна копия myVar
, и оба родительского и дочернего классов будут разделять их.
До и до тех пор, пока дочерний класс не станет инициатором.
Ответ 4
Вот ссылка на Java Specification - раздел 8.7 рассказывает о статических инициализаторах. Он дает хорошие сведения о том, как они должны функционировать и порядок, в котором они вызываются. http://docs.oracle.com/javase/specs/jls/se7/html/jls-8.html#jls-8.7
Ответ 5
Когда мы делаем
class Base {
public static int myVar = 0;
static {
System.out.println("Base");
}
}
класс Derived extends Base {
static {
System.out.println("Derived");
Base.myVar = 9;
}
}
открытый класс StaticBlock {
public static void main(String[] args) {
System.out.println(Base.myVar);
System.out.println(Derived.myVar);
}
}
Выход будет
Base
0
0
Это означает, что статический блок производного класса не выполняется..!!