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

В Java порядок выполнения конструкторов и блоков инициализации подчиняется строгой иерархии. Это важно для правильной инициализации объектов, особенно в наследуемых классах.

🧠 Общий порядок инициализации объектов в Java:

Когда создаётся объект подкласса, выполняются следующие шаги (в этом порядке):

  1. **Статические блоки инициализации суперкласса
    **
  2. **Статические блоки инициализации подкласса
    **
  3. **Нестатические поля и блоки инициализации суперкласса
    **
  4. **Конструктор суперкласса
    **
  5. **Нестатические поля и блоки инициализации подкласса
    **
  6. **Конструктор подкласса
    **

🔷 Подробный порядок вызовов:

1. Статические инициализации (один раз при первом использовании класса):

  • Статические поля и static-блоки суперкласса

  • Статические поля и static-блоки подкласса

Выполняются только один раз, когда класс загружается в JVM.

2. При создании объекта:

➤ Сначала выполняется в суперклассе:

  • Инициализация **нестатических полей
    **
  • Выполнение **нестатических блоков инициализации
    **
  • Вызов **конструктора суперкласса
    **

➤ Затем выполняется в подклассе:

  • Инициализация **нестатических полей
    **
  • Выполнение **нестатических блоков
    **
  • Вызов **конструктора подкласса
    **

🧩 Пример с выводом:

class Parent {
static {
System.out.println("1. Static block of Parent");
}
{
System.out.println("3. Instance block of Parent");
}
Parent() {
System.out.println("4. Constructor of Parent");
}
}
class Child extends Parent {
static {
System.out.println("2. Static block of Child");
}
{
System.out.println("5. Instance block of Child");
}
Child() {
System.out.println("6. Constructor of Child");
}
}
public class Test {
public static void main(String\[\] args) {
new Child();
}
}

📤 Вывод:

1. Static block of Parent // Загрузка суперкласса

2. Static block of Child // Загрузка подкласса

3. Instance block of Parent // При создании объекта

4. Constructor of Parent

5. Instance block of Child

6. Constructor of Child

🔧 Объяснение:

Этап Где происходит
static блоки суперкласса При первом использовании родительского класса
--- ---
static блоки подкласса Затем при загрузке подкласса
--- ---
Нестатические блоки суперкласса При создании объекта
--- ---
Конструктор суперкласса После нестатических блоков
--- ---
Нестатические блоки подкласса После суперкласса
--- ---
Конструктор подкласса В самом конце
--- ---

📌 Примечания:

  • Блоки инициализации ({ ... }) выполняются в порядке появления в коде.

  • Если конструктор подкласса явно вызывает super(...), то сначала вызывается этот конструктор суперкласса.

  • Можно использовать много блоков инициализации — они выполняются сверху вниз (в порядке написания).

✅ Пример с полями:

class A {
int x = initX();
int initX() {
System.out.println("Init A.x");
return 1;
}
}
class B extends A {
int y = initY();
int initY() {
System.out.println("Init B.y");
return 2;
}
public static void main(String\[\] args) {
new B();
}
}

📤 Вывод:

Init A.x
Init B.y

📚 Вывод

Этап Порядок выполнения при new Child()
1. static блоки Сначала суперкласс, потом подкласс (1 раз при загрузке)
--- ---
2. instance блоки и поля Сначала суперкласс, потом подкласс
--- ---
3. Конструкторы Сначала суперкласс, потом подкласс
--- ---

🛠 Совет

  • Не перегружай классы сложной инициализацией — это делает порядок сложным.

  • Используй super(...) в конструкторе подкласса, если нужно явно выбрать конструктор суперкласса.

  • Не используй this в конструкторе до завершения super(...), иначе объект ещё не полностью инициализирован.