JavaRush /Курсы /Модуль 1. Java Syntax /Порядок инициализации при использовании конструкторов и с...

Порядок инициализации при использовании конструкторов и статических блоков

Модуль 1. Java Syntax
14 уровень , 3 лекция
Открыта

Давай разберемся в очередности выполнения кода в блоках инициализации (статических и не статических), конструкторах, а также инициализации статических и не статических полей. Разбираться будем на практике, выполняя код.

На входе у нас есть класс с полным набором всевозможных элементов:


public class MyClass {
    static {
        System.out.println("Статический блок №1.");
    }

    public static String staticField = setStaticField();

    public MyClass() {
        System.out.println("Конструктор.");
    }

    static {
        System.out.println("Статический блок №2.");
    }

    {
        System.out.println("Блок инициализации №1.");
    }

    public String nonStaticField = setNonStaticField();

    {
        System.out.println("Блок инициализации №2.");
    }

    private String setNonStaticField() {
        System.out.println("Не статическое поле.");
        return "nonStaticField";
    }

    private static String setStaticField() {
        System.out.println("Статическое поле.");
        return "staticField";
    }

    public static void print() {
        System.out.println("Метод print.");
    }
}

Теперь рядом с этим классом создадим еще один, в нем метод main и запустим его:


public class Solution {
    public static void main(String args[]) {
        System.out.println("hello");
    }
}
В выводе нет ничего из класса MyClass. Поскольку к MyClass не было обращений, класс вообще не был загружен. Попробуем теперь вызвать у класса MyClass статический метод print(). Дважды.

public class Solution {
    public static void main(String args[]) {
        MyClass.print();
        MyClass.print();
    }
}

Вывод:

Статический блок №1.
Статическое поле.
Статический блок №2.
Метод print.
Метод print.

Выполнились только статические блоки инициализации и инициализировалось статическое поле. Причем произошло это только один раз. Дело в том, что во время второго вызова метода print() класс уже был загружен. Запоминаем: статические поля и блоки инициализации выполняются один раз при первом взаимодействии с классом.

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

Далее вместо вызова статического метода попробуем создать два объекта нашего класса:


public class Solution {
    public static void main(String args[]) {
        new MyClass();
        System.out.println();
        new MyClass();
    }
}

Вывод:

Статический блок №1.
Статическое поле.
Статический блок №2.
Блок инициализации №1.
Не статическое поле.
Блок инициализации №2.
Конструктор.

Блок инициализации №1.
Не статическое поле.
Блок инициализации №2.
Конструктор.

Сначала один раз идут статические блоки и поля, потом при каждом создании объекта отрабатывают нестатические блоки, поля, и конструктор. И если поля и блоки инициализации отрабатывают в порядке их объявления, то конструктор отрабатывает в конце, не зависимо от того в каком месте он объявлен.

Усложним пример, и возьмем два класса, причем один из них наследует другой:


public class ParentClass {
    static {
        System.out.println("Статический блок №1 родительского класса.");
    }

    public static String parentStatic = setParentStatic();

    static {
        System.out.println("Статический блок №2 родительского класса.");
    }

    {
        System.out.println("Блок инициализации №1 родительского класса.");
    }

    public String parentNonStatic = setParentNonStatic();

    {
        System.out.println("Блок инициализации №2 родительского класса.");
    }

    public ParentClass() {
        System.out.println("Конструктор родительского класса.");
    }

    private String setParentNonStatic() {
        System.out.println("Не статическое поле родительского класса.");
        return "parentNonStatic";
    }

    private static String setParentStatic() {
        System.out.println("Статическое поле родительского класса.");
        return "parentStatic";
    }

    public String setChildNonStatic1() {
        System.out.println("Не статическое поле дочернего класса №1.");
        return "childNonStatic2" + parentNonStatic;
    }
}
 
public class ChildClass extends ParentClass {
    static {
        System.out.println("Статический блок №1 дочернего класса.");
    }

    public static String childStatic = setChildStatic();

    static {
        System.out.println("Статический блок №2 дочернего класса.");
    }

    public String childNonStatic1 = setChildNonStatic1();

    {
        System.out.println("Блок инициализации №1 дочернего класса.");
    }

    public String childNonStatic2 = setChildNonStatic2();

    {
        System.out.println("Блок инициализации №2 дочернего класса.");
    }

    public ChildClass() {
        System.out.println("Конструктор дочернего класса.");
    }

    private String setChildNonStatic2() {
        System.out.println("Не статическое поле дочернего класса №2.");
        return "childNonStatic";
    }

    private static String setChildStatic() {
        System.out.println("Статическое поле дочернего класса.");
        return "childStatic";
    }
}

Создадим два объекта дочернего класса:


public class Solution {
    public static void main(String[] args) {
        new ChildClass();
        System.out.println();
        new ChildClass();
    }
}

Вывод:

Статический блок №1 родительского класса.
Статическое поле родительского класса.
Статический блок №2 родительского класса.
Статический блок №1 дочернего класса.
Статическое поле дочернего класса.
Статический блок №2 дочернего класса.
Блок инициализации №1 родительского класса.
Не статическое поле родительского класса.
Блок инициализации №2 родительского класса.
Конструктор родительского класса.
Не статическое поле дочернего класса №1.
Блок инициализации №1 дочернего класса.
Не статическое поле дочернего класса №2.
Блок инициализации №2 дочернего класса.
Конструктор дочернего класса.

Блок инициализации №1 родительского класса.
Не статическое поле родительского класса.
Блок инициализации №2 родительского класса.
Конструктор родительского класса.
Не статическое поле дочернего класса №1.
Блок инициализации №1 дочернего класса.
Не статическое поле дочернего класса №2.
Блок инициализации №2 дочернего класса.
Конструктор дочернего класса.

Из нового видим, что статические блоки и переменные родительского класса отрабатывают перед статическими блоками и переменными дочернего класса. То же самое и с нестатическими блоками и переменными и конструкторами: сначала родительский класс, затем дочерний. Для чего это нужно, можно посмотреть на примере поля childNonStatic1 дочернего класса. Для его инициализации используется метод родительского класса, а этот метод использует переменную родительского класса, соответственно во время иниицализации поля childNonStatic1, родительский класс с его методами уже должен быть загружен, и переменные родительского класса должны быть проинициализированы.

На практике ты можешь и не встретить классов, содержащих сразу все перечисленные элементы, но помнить, что за чем инициализируется будет полезно. А еще это часто спрашивают на собеседованиях 😊

14
Задача
Java Syntax Pro, 14 уровень, 3 лекция
Недоступна
Изучаем методы класса Collections, часть 1
Изучаем методы класса Collections, часть 1
14
Задача
Java Syntax Pro, 14 уровень, 3 лекция
Недоступна
Изучаем методы класса Collections, часть 2
Изучаем методы класса Collections, часть 2
14
Задача
Java Syntax Pro, 14 уровень, 3 лекция
Недоступна
Изучаем методы класса Collections, часть 3
Изучаем методы класса Collections, часть 3
Комментарии (14)
ЧТОБЫ ПОСМОТРЕТЬ ВСЕ КОММЕНТАРИИ ИЛИ ОСТАВИТЬ КОММЕНТАРИЙ,
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ
Валерка Ферум Уровень 32
27 марта 2026
Статики первые, включая Родителя Не статики вторые, включая Родителя Все понятно
Руслан Уровень 48
20 июля 2025
Короче ребят обьясню просто при первом обращении к классу - что значит обращении это либо метод main с которого запускается программа либо из любого другого класса обращение к нашему классу как показано на примере выше мы создали обьект другого класса и тем самым обратились к нему и теперь обьясню максимально понятно Вот мы обратились к классу когда создали его обьект и теперь сначала создаются статик обьекты потом они инициализируются как в самих переменных так и в самих статик блоках.Все теперь все статическое отработало теперь начинает работать все не статическое точно по такой же логике сначала создание переменных потом их инициализация и все по порядку как написано в коде и ТОЛЬКО В САМОМ КОНЦЕ Отработает конструктор. У вас наверное щяс будет вопрос но почему сразу все не статик начинает отрабатывать а я вам отвечу - потому что мы создали и каждый раз когда мы создаем обьект все не статик начинает создаваться точно таким же образом как я написал чуть выше и ЭТО БУДЕТ ПРИ КАЖДОМ СОЗДАНИИ ОБЬЕКТА!!!! Но главное запомнить все статик поля иницализируются 1 единственный раз при обращении к классу а дальше уже значения статик полей подменяется на значения которые мы ему дадим при повторном обращении к классу.ВОТ. А с наследованием таже самая логика: Сначала все у родителя А только потом все у потомка!!!!! Надеюсь понятно обьяснил😅😅
Александр Уровень 23
8 января 2025
Два раза прочел. Ничего не понял и пошел читать третий раз
Сергей Титов Уровень 1
29 февраля 2024
Нормально всё описано. Тут больше и не скажешь. Зато если это всё исполнить через отладчик, пошагово, то всё на свои места становится. Если вообще тяжко, распечатываем всё на листиках склеиваем, рисуем стрелочки откуда что взялось. Сделал так и этак, ощутил кипение мозга,чашечка кофе - и озарение!😅
Andrzej Уровень 32 Expert
11 ноября 2023
Тот случай, когда лекцию лучше переписать, а что бы понять - лучше поискать на других ресурсах. Таких мест пока на курсе почти не было, но это - именно такое. Огромный громоздкий кусок кода с минимальными пояснениями - явно не лучший вариант объяснения.
sTra1cs Уровень 24
6 ноября 2023
Подскажите плиз: Каким образов при вызове из метода мейн ->MyClass.print() - вызывается все что указано в примере ? Как это работает ?
Виктор Ш Уровень 73
14 апреля 2025
В Java, когда ты впервые обращаешься к классу, например: MyClass.print(); — JVM загружает класс в память. И в момент загрузки происходят следующие шаги: Что выполняется при первом обращении к классу: Выполняются статические блоки static {} — в порядке их объявления Инициализируются статические поля Только после этого выполняется то, что ты попросил — print()
Vitalii Уровень 3 Expert
2 августа 2023
Очень громоздкий кусок кода для понимания. Вобщем, только запутывает, а не проясняет (
Андрей Уровень 101 Expert
10 сентября 2022
Про блок инициализации уже была лекция? Первый раз вижу это понятие.
Екатерина Уровень 70 Expert
2 августа 2022
Непонятна идея материала, нет value, по крайней мере в данный момент) Возможно будет понятно дальше но сейчас этот текст воспринимается как рыбка за стеклом булькает)) И меня одну смущает метод без имени но статичный?) Я видимо чтото упустила по лекциям. По сути гугл мне сказал проще, запомню пока как данность) Когда в классе присутствуют все три метода инициализации (конструкторы, нестатические блоки инициализации и статические блоки инициализации), статические всегда выполняются первыми (когда класс загружается в память) в порядке их объявления, затем выполняются нестатические блоки инициализации в порядке, в котором они объявлены, а после них – конструкторы. источник - https://habr.com/ru/post/480544/
Артемий Уровень 26
24 апреля 2022
Это логично.