Статическое ключевое слово в Java

class A {
    static {
        System.out.println("A-SIB");
    }
    static void test(){
        System.out.println("A-test");
    }
}

class B extends A  {
    static {
        System.out.println("B-SIB");
    }
}

class C  {
    public static void main(String args []){
        B.test();
    }
}

Когда я запускал класс C, я думал, что A-SIB, B-SIB и A-test будут напечатаны, но B-SIB не было на выходе. Может кто-нибудь объяснить, почему?

Ответ 1

Class B не реализует (aka "hide" ) метод static test, поэтому начальное выполнение начинается с Class A (следовательно, A-SIB); а затем с помощью метода test в A (следовательно, "A-тест" ). Если вы переопределите test в Class B, вы получите B-тест A-SIB B-SIB

Ответ 2

Здесь JLS говорит о инициализации класса:

Инициализация класса состоит в выполнении его статических инициализаторов и инициализаторов для статических полей (переменных класса), объявленных в классе.

Инициализация интерфейса состоит в выполнении инициализаторов для полей (констант), объявленных в интерфейсе.

Прежде чем инициализировать класс, его прямой суперкласс должен быть инициализирован, но интерфейсы, реализованные классом, не инициализируются. Аналогично, суперинтерфейсы интерфейса не инициализируются до инициализации интерфейса.

Класс или тип интерфейса T будет инициализирован непосредственно перед первым вхождением любого из следующих значений:

  • T - это класс и создается экземпляр T.
  • T - класс, и статический метод, объявленный T, вызывается.
  • Назначено статическое поле, объявленное T.
  • Используется статическое поле, объявленное T, и поле не является постоянной переменной (§4.12.4).
  • T - класс верхнего уровня (§7.6), и выполняется оператор утверждения (§14.10), лексически вложенный в T (§8.1.3).

Ссылка на статическое поле (§8.3.1.1) вызывает инициализацию только класса или интерфейса, который фактически объявляет его, даже если он может быть указан через имя подкласса, подинтерфейс или класс, который реализует интерфейс.

В этом случае все, что вы делаете в C с классом B, вызывается статическим методом test(). Но этот метод объявлен в A, а не в B. Таким образом, JVM не инициализирует класс B и, следовательно, не вызывает его статический блок инициализатора.

Обратите внимание, что класс B ссылается на байтовый код C и загружается JVM. Но это не инициализировано. Если вы удалите B.class и попытаетесь запустить C, вы получите исключение.