JavaRush /Курси /JAVA 25 SELF /Ініціалізація об’єкта: порядок ініціалізації

Ініціалізація об’єкта: порядок ініціалізації

JAVA 25 SELF
Рівень 14 , Лекція 5
Відкрита

1. Порядок ініціалізації об’єкта в Java: хто перший, хто останній?

Створення об’єкта в Java — це не просто «виділити пам’ять і записати туди значення». Це цілий ритуал із чітким порядком дій. Якщо уявити процес ініціалізації як запуск ракети, то кожен ступінь має суворо визначене місце.

Коли ви пишете:

Person vasya = new Person("Вася", 30);

Java виконує такі кроки:

  1. Виділяє пам’ять для об’єкта і присвоює всім полям значення за замовчуванням.
  2. Виконує явну ініціалізацію полів (якщо ви задали значення прямо під час оголошення).
  3. Виконує всі нестатичні (звичайні) блоки ініціалізації — у тому порядку, у якому вони написані в класі.
  4. Виконує тіло конструктора, який ви викликали через new.

Розгляньмо кожен крок докладно.

2. Ініціалізація полів

Значення за замовчуванням

Коли об’єкт щойно створений (ще до того, як ви щось явно присвоїли), усі його поля отримують значення за замовчуванням:

Тип поля Значення за замовчуванням
int, short, byte, long
0
float, double
0.0
boolean
false
char
'\u0000' (нульовий символ)
Посилальні типи (String, інші об’єкти)
null

Явна ініціалізація

Якщо ви під час оголошення поля одразу присвоюєте йому значення, воно встановлюється після значень за замовчуванням, але до виконання конструктора.

public class Person {
    private String name = "Безіменний";
    private int age = 18;
}

Якщо ви створите об’єкт через порожній конструктор, ці значення залишаться. Якщо через конструктор із параметрами — ймовірно, вони будуть перезаписані.

3. Блоки ініціалізації: навіщо вони потрібні та як працюють

У Java можна оголошувати так звані нестатичні (звичайні) блоки ініціалізації. Вони виконуються щоразу під час створення об’єкта, одразу після ініціалізації полів, але до конструктора.

Синтаксис:

public class Person {
    {
        System.out.println("Виконується нестатичний блок ініціалізації!");
    }
}

Якщо в класі кілька таких блоків, вони виконуються у тому порядку, у якому написані.

Приклад із кількома блоками

public class Person {
    private String name = "Безіменний";

    {
        System.out.println("Блок 1: name = " + name);
        name = "Загадка";
    }

    {
        System.out.println("Блок 2: name = " + name);
    }

    public Person() {
        System.out.println("Конструктор: name = " + name);
    }
}

Якщо створити об’єкт:

Person p = new Person();

Виведення буде таким:

Блок 1: name = Безіменний
Блок 2: name = Загадка
Конструктор: name = Загадка

Навіщо потрібні блоки ініціалізації?

На практиці блоки ініціалізації використовують рідко. Зазвичай усе, що можна зробити в блоці, можна зробити або під час оголошення поля, або в конструкторі. Однак інколи (наприклад, якщо у вас кілька конструкторів, а частина логіки ініціалізації має бути спільною для всіх) блоки ініціалізації стають у пригоді.

4. Конструктор: фінальний акорд ініціалізації

Після того як усі поля отримали значення (за замовчуванням або явно) і відпрацювали всі блоки ініціалізації, викликається конструктор — той самий, який ви вказали після new.

У конструкторі ви зазвичай присвоюєте підсумкові значення полів, приймаєте параметри та виконуєте іншу ініціалізацію, яка залежить від вхідних даних.

public class Person {
    private String name;
    private int age;

    public Person(String name, int age) {
        System.out.println("Конструктор: name = " + name + ", age = " + age);
        this.name = name;
        this.age = age;
    }
}

5. Демонстрація повного порядку ініціалізації

Напишімо клас, який чітко покаже, у якому порядку відбувається ініціалізація.

public class Person {
    private String name = "Безіменний";
    private int age = 18;

    {
        System.out.println("Блок ініціалізації: name = " + name + ", age = " + age);
        age = 21;
    }

    public Person() {
        System.out.println("Конструктор без параметрів: name = " + name + ", age = " + age);
    }

    public Person(String name, int age) {
        System.out.println("Конструктор із параметрами: name = " + name + ", age = " + age);
        this.name = name;
        this.age = age;
    }

    public void printInfo() {
        System.out.println("Person: name = " + name + ", age = " + age);
    }
}

А тепер у нашому основному класі (наприклад, Main):

public class Main {
    public static void main(String[] args) {
        System.out.println("Створюємо об’єкт p1:");
        Person p1 = new Person();
        p1.printInfo();

        System.out.println("\nСтворюємо об’єкт p2:");
        Person p2 = new Person("Петро", 30);
        p2.printInfo();
    }
}

Виведення буде приблизно таким:

Створюємо об’єкт p1:
Блок ініціалізації: name = Безіменний, age = 18
Конструктор без параметрів: name = Безіменний, age = 21
Person: name = Безіменний, age = 21

Створюємо об’єкт p2:
Блок ініціалізації: name = Безіменний, age = 18
Конструктор із параметрами: name = Петро, age = 30
Person: name = Петро, age = 30

Зверніть увагу: під час виконання конструктора з параметрами поля ще мають попередні значення (ті, що після блоку ініціалізації). У наведеному println виводяться значення параметрів name та age, а поля оновлюються після присвоєнь.

6. Діаграма порядку ініціалізації

Ось невелика схема (блок‑схема) для наочності:

flowchart TD
    A[Виділення пам’яті, значення за замовчуванням] --> B[Явна ініціалізація полів]
    B --> C[Виконання нестатичних блоків ініціалізації]
    C --> D[Виконання конструктора]
    D --> E[Об’єкт готовий до використання]

7. Особливості та нюанси

Статичні поля і статичні блоки

У цій лекції ми говоримо лише про нестатичні (звичайні) поля й блоки. Статичні поля та статичні блоки ініціалізуються один раз під час завантаження класу, а не під час кожного створення об’єкта. Докладніше про них поговоримо в темах про інкапсуляцію.

Коли що ініціалізується?

  • Поля — під час кожного створення об’єкта.
  • Блоки ініціалізації — під час кожного створення об’єкта.
  • Статичні поля й блоки — лише один раз під час завантаження класу.

Чи можна звертатися до полів у блоках ініціалізації?

Так, можна! Важливо пам’ятати, що якщо поле оголошене нижче блока, воно вже існує, але до явної ініціалізації матиме значення за замовчуванням.

8. Типові помилки під час ініціалізації об’єктів

Помилка № 1: Очікування, що поля буде ініціалізовано до їх оголошення.
У Java порядок оголошення полів і блоків ініціалізації в класі має значення. Якщо ви у блоці ініціалізації звертаєтеся до поля, яке оголошено нижче, воно вже існує, але ще не ініціалізоване явно — матиме значення за замовчуванням.

Помилка № 2: Дублювання ініціалізації в блоках і конструкторах.
Новачки часто повторюють одну й ту саму логіку і в блоці, і в конструкторі. Краще використовувати або блок, або конструктор, або викликати один конструктор з іншого через this(...).

Помилка № 3: Очікування, що статичні поля ініціалізуються під час кожного створення об’єкта.
Статичні поля й блоки працюють інакше — їх ініціалізують лише один раз під час завантаження класу.

Помилка № 4: Використання неініціалізованих посилальних полів.
Якщо ви забули явно ініціалізувати посилальне поле (наприклад, String name;), то воно дорівнюватиме null доти, доки ви не присвоїте йому значення явно в блоці ініціалізації або в конструкторі.

1
Опитування
Класи та конструктори, рівень 14, лекція 5
Недоступний
Класи та конструктори
Класи та конструктори
Коментарі
ЩОБ ПОДИВИТИСЯ ВСІ КОМЕНТАРІ АБО ЗАЛИШИТИ КОМЕНТАР,
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ