Подтвердить что ты не робот

Поведение статических блоков с наследованием

Я пытаюсь использовать статические блоки следующим образом:

У меня есть базовый класс 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. Может ли кто-нибудь объяснить это поведение? Кроме того, если я хочу, чтобы мои производные классы устанавливали значения для статической переменной, как я могу это достичь?

4b9b3361

Ответ 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 Это означает, что статический блок производного класса не выполняется..!!