В каком порядке делают статические блоки инициализатора / блоки инициализатора экземпляра в выполненном Java?

Скажите, что проект содержит несколько классов, каждый из которых имеет статический блок инициализатора. В каком порядке работают те блоки? Я знаю, что в классе, такие блоки выполняются в порядке, они появляются в коде. Я считал, что это - то же через классы, но некоторый код кода, который я написал, не соглашается с этим. Я использовал этот код:

package pkg;

public class LoadTest {
    public static void main(String[] args) {
        System.out.println("START");
        new Child();
        System.out.println("END");
    }
}

class Parent extends Grandparent {
    // Instance init block
    {
        System.out.println("instance - parent");
    }

    // Constructor
    public Parent() {
        System.out.println("constructor - parent");
    }

    // Static init block
    static {
        System.out.println("static - parent");
    }
}

class Grandparent {
    // Static init block
    static {
        System.out.println("static - grandparent");
    }

    // Instance init block
    {
        System.out.println("instance - grandparent");
    }

    // Constructor
    public Grandparent() {
        System.out.println("constructor - grandparent");
    }
}

class Child extends Parent {
    // Constructor
    public Child() {
        System.out.println("constructor - child");
    }

    // Static init block
    static {
        System.out.println("static - child");
    }

    // Instance init block
    {
        System.out.println("instance - child");
    }
}

и получил этот вывод:

ЗАПУСТИТЬ
статичный - прародитель
статичный - родитель
статичный - ребенок
экземпляр - прародитель
конструктор - прародитель
экземпляр - родитель
конструктор - родитель
экземпляр - ребенок
конструктор - ребенок
КОНЕЦ

Очевидный ответ от этого - то, что блоки родителей работают перед их детским, но это могло просто быть совпадением и не помогает, если два класса не находятся в той же иерархии.

Править:

Я изменил свой пример кода путем добавления этого к LoadTest.java:

class IAmAClassThatIsNeverUsed {
    // Constructor
    public IAmAClassThatIsNeverUsed() {
        System.out.println("constructor - IAACTINU");
    }

    // Instance init block
    {
        System.out.println("instance - IAACTINU");
    }

    // Static init block
    static {
        System.out.println("static - IAACTINU");
    }
}

Как подразумевается именем класса, я никогда не ссылался на новый класс нигде. Новая программа произвела тот же вывод как старый.

91
задан slim 8 June 2017 в 12:18
поделиться

3 ответа

[

] Статический инициализатор для класса запускается при первом обращении к нему, либо для создания экземпляра, либо для доступа к статическому методу или полю [

]. [

] Итак, для нескольких классов это полностью зависит от кода, который запускается, чтобы вызвать загрузку этих классов. [

]
60
ответ дан 24 November 2019 в 06:46
поделиться

Смотрите раздел 12.4 и 12.5 JLS версии 8, они вдаются в кровавые подробности обо всем этом (12.4 для статических и 12.5 для, например, переменных).

Для статической инициализации (раздел 12.4):

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

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

(и несколько пунктов о слове ласка)

.
92
ответ дан 24 November 2019 в 06:46
поделиться

ответы Кита и Криса великолепны, я просто добавляю некоторые подробности к моему конкретному вопросу.

Статические блоки init выполняются в том порядке, в котором инициализируются их классы. Итак, какой это порядок? В JLS 12.4.1:

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

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

Вызов определенных отражающих методов в классе и в пакете java.lang.reflect также вызывает инициализацию класса или интерфейса. Класс или интерфейс не инициализируется ни при каких других обстоятельствах.

Для иллюстрации приведен обзор того, что происходит в данном примере:

  1. Enter main
  2. Print "START"
  3. Attempt to create first instance of Child, which requires initialization of Child
  4. Atting to initialize Child causes initialization of Parent
  5. Atting to initialize Parent causes initialization of Grandparent
  6. At the begin of initialization of Grandparent, Статический блок инициализации дедушки и бабушки выполняется
  7. Технически, Объект получает последнее слово в цепочке инициализации в силу того, что является родителем дедушки и бабушки, но ему нечего делать
  8. После того, как статический блок инициализации дедушки и бабушки заканчивается, Программа возвращается к статическому блоку инициализации Parent
  9. После окончания статического блока инициализации Parent, программа возвращается к статическому блоку инициализации Child
  10. В этот момент происходит инициализация Child, поэтому ее конструктор может продолжить работу
  11. Так как на IAmAClassThatIsNeverUsed никогда не ссылаются, ни один его код никогда не выполняется, включая статические блоки инициализаторов
  12. Остальная часть этого прохода не касается статических инициализаторов и включается только для полноты
  13. Child's конструктор неявно вызывает super() (i. e., Конструктор родителя)
  14. Конструктор родителя неявно вызывает super() (т.е, Конструктор дедушки и бабушки)
  15. Конструктор дедушки и бабушки делает то же самое, что не имеет никакого эффекта (опять же, Объекту нечего делать)
  16. Сразу после вызова конструктора дедушки и бабушки в super() приходит блок инициализатора экземпляра дедушки и бабушки
  17. Остальной конструктор дедушки и бабушки выполняется, и конструктор завершается
  18. Программа возвращается обратно в конструктор родителя, сразу после вызова super() (т.е., Конструктор дедушки и бабушки) разрешает
  19. Как и выше, инициализатор экземпляра родительского делает свое дело, а его конструктор завершает
  20. Аналогично, программа возвращается и завершает конструктор ребенка
  21. На этом этапе программа возвращается к своему конструктору, объект инстанцирован
  22. Печать "END"
  23. Терминал обычно
32
ответ дан 24 November 2019 в 06:46
поделиться
Другие вопросы по тегам:

Похожие вопросы: