Поведение статических блоков с наследованием
Я пытаюсь использовать статические блоки, как это:
У меня есть базовый класс под названием 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);
}
Это печатает выход как 0 0
где, как я и ожидал 10 0
, Может кто-нибудь объяснить это поведение? Кроме того, если я хочу, чтобы мои производные классы устанавливали значения для статической переменной, как я могу этого добиться?
5 ответов
Насколько я понимаю. Вы не звоните 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), и выполняется оператор assert (§14.10), лексически вложенный в T (§8.1.3).
Статические блоки инициализатора не запускаются, пока класс не инициализирован. См. Параграфы 8.7 Спецификации языка Java (Статические инициализаторы) и 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.
Существует одна копия myVar
и родительский и дочерний класс будут разделены одинаково. До тех пор, пока дочерний класс не будет инициализирован.
Когда мы делаем
class Base {
public static int myVar = 0;
static {
System.out.println("Base");
}
}
class Derived extends Base {
static {
System.out.println("Derived");
Base.myVar = 9;
}
}
public class StaticBlock {
public static void main(String[] args) {
System.out.println(Base.myVar);
System.out.println(Derived.myVar);
}
}
Выход будетBase
0
0
Это означает, что статический блок производного класса не выполняется..!!
Вот ссылка на спецификацию Java - в разделе 8.7 говорится о статических инициализаторах. Это дает хорошие подробности о том, как они должны функционировать и в каком порядке их вызывают. http://docs.oracle.com/javase/specs/jls/se7/html/jls-8.html