В каком порядке запускаются статические /экземплярные инициализаторы в 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");
    }
}

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

  

START
  статичный - прародитель
  статический - родительский
  статичный - ребенок
  пример - прародитель
  конструктор - прародитель
  экземпляр - родитель
  конструктор - родитель
  экземпляр - ребенок
  конструктор - ребенок
  END

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

EDIT:

Я изменил свой пример кода, добавив его в 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");
    }
}

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

86 голосов | спросил Pops 5 Jpm1000000pmTue, 05 Jan 2010 20:01:50 +030010 2010, 20:01:50

7 ответов


0

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

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

ответил Chris Jester-Young 5 Jpm1000000pmTue, 05 Jan 2010 20:05:01 +030010 2010, 20:05:01
0

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

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

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

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

(и несколько предложений слов ласки)

ответил Keith Randall 5 Jpm1000000pmTue, 05 Jan 2010 20:07:18 +030010 2010, 20:07:18
0

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

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

  

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

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

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

Чтобы проиллюстрировать, вот пошаговое описание того, что происходит в примере:

  1. Введите основной
  2. Распечатать "START"
  3. Попытка создать первый экземпляр Child, который требует инициализации Child
  4. Попытка инициализировать дочерний элемент вызывает инициализацию родительского элемента
  5. Попытка инициализировать Parent вызывает инициализацию Grandparent
  6. В начале инициализации дедушки запускается блок статической инициализации дедушки
  7. Технически, объект получает последнее слово в цепочке инициализации благодаря тому, что является родителем дедушки, но ему нечего внести
  8. После того, как статический блок инициализации дедушки заканчивается, программа возвращается к статическому блоку инициализации Родителя
  9. После завершения блока статической инициализации Parent программа возвращается к блоку статической инициализации Child
  10. На этом этапе Child инициализируется, поэтому его конструктор может продолжить работу
  11. Поскольку на IAmAClassThatIsNeverUsed никогда не ссылаются, никогда не выполняется ни один из его кодов, включая блоки статических инициализаторов
  12. Остальная часть этого пошагового руководства не касается статических инициализаторов и включена только для полноты
  13. Детский конструктор неявно вызывает super () (т.е. конструктор Parent)
  14. Родительский конструктор неявно вызывает super () (т.е. конструктор дедушки)
  15. Конструктор бабушки и дедушки делает то же самое, что не имеет никакого эффекта (опять же, объект не имеет ничего, чтобы внести свой вклад)
  16. Сразу после вызова конструктора Grandparent для super () приходит блок инициализатора экземпляра Grandparent
  17. Остальная часть конструктора Grandparent выполняется, и конструктор завершается
  18. Программа возвращается к конструктору Parent сразу после того, как ее вызов super () (то есть конструктор Grandparent) разрешается
  19. Как и выше, инициализатор экземпляра Parent делает свое дело, а его конструктор завершает работу
  20. Аналогично, программа возвращается и завершает конструктор Child.
  21. На данный момент объект был создан
  22. Распечатать "END"
  23. обычно завершается
ответил Pops 5 Jpm1000000pmTue, 05 Jan 2010 21:38:51 +030010 2010, 21:38:51
0

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

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

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

ответил Bala 1 Maypm14 2014, 16:43:54
0

Вы можете иметь несколько статических инициализаторов и инициализаторов экземпляров в одном классе, поэтому

  • Статические инициализаторы вызываются в текстовом порядке, в котором они объявлены (из 12.4.2 )
  • Инициализаторы экземпляра вызываются в текстовом порядке, в котором они объявлены (из 12,5 )

Каждый выполняется так, как если бы это был один блок.

ответил Martin Tapp 25 FebruaryEurope/MoscowbTue, 25 Feb 2014 22:21:58 +0400000000pmTue, 25 Feb 2014 22:21:58 +040014 2014, 22:21:58
0

http://docs.oracle.com/javase/tutorial/Java /javaOO /initial.html

пожалуйста, проверьте документацию Java.

затем четко упомянуто, независимо от того, как могут быть статические блоки, они будут выполняться как один блок в порядке их появления

Итак,

Насколько я понимаю, java смотрит на ваш код как на

static{
i=1;
i=2;
}

static int i;

именно поэтому вы получаете вывод 2

надеюсь, что это полезно

ответил Avinash Perla 13 Maypm15 2015, 13:37:45
0

В одном случае статический блок не будет вызываться.

class Super {
    public static int i=10;
}
class Sub extends Super {
    static {
        system.out.println("Static block called");
    }
}
class Test {
    public static void main (String [] args) {
        system.out.println(Sub.i);
    } 
}

Приведенный выше код выводит 10

ответил Java Main 17 42016vEurope/Moscow11bEurope/MoscowThu, 17 Nov 2016 12:50:11 +0300 2016, 12:50:11

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

Популярные теги

security × 330linux × 316macos × 2827 × 268performance × 244command-line × 241sql-server × 235joomla-3.x × 222java × 189c++ × 186windows × 180cisco × 168bash × 158c# × 142gmail × 139arduino-uno × 139javascript × 134ssh × 133seo × 132mysql × 132