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

Я пытаюсь использовать статические блоки, как это:

У меня есть базовый класс под названием 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

Другие вопросы по тегам