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
В классе Solution объявлены методы: copy(ArrayList, ArrayList), addAll(ArrayList, String...), replaceAll(ArrayList, String, String). Тебе нужно переписать их реализацию, используя при этом только соответствующие методы класса Collections. Параметр String... означает
14
Задача
Java Syntax Pro, 14 уровень, 3 лекция
Недоступна
Изучаем методы класса Collections, часть 2
В классе Solution объявлены методы: reverse(ArrayList), sort(ArrayList), rotate(ArrayList, int), shuffle(ArrayList). Тебе нужно разобраться, что делают методы, переписать их реализацию, используя при этом только соответствующие методы класса Collections.
14
Задача
Java Syntax Pro, 14 уровень, 3 лекция
Недоступна
Изучаем методы класса Collections, часть 3
В классе Solution объявлены методы: min(ArrayList), max(ArrayList), frequency(ArrayList, Integer), binarySearch(ArrayList, Integer). Тебе нужно разобраться, что делают методы, переписать их реализацию, используя при этом только соответствующие методы класса Collec
Комментарии (13)
ЧТОБЫ ПОСМОТРЕТЬ ВСЕ КОММЕНТАРИИ ИЛИ ОСТАВИТЬ КОММЕНТАРИЙ,
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ
Руслан Уровень 48
20 июля 2025
Короче ребят обьясню просто при первом обращении к классу - что значит обращении это либо метод main с которого запускается программа либо из любого другого класса обращение к нашему классу как показано на примере выше мы создали обьект другого класса и тем самым обратились к нему и теперь обьясню максимально понятно Вот мы обратились к классу когда создали его обьект и теперь сначала создаются статик обьекты потом они инициализируются как в самих переменных так и в самих статик блоках.Все теперь все статическое отработало теперь начинает работать все не статическое точно по такой же логике сначала создание переменных потом их инициализация и все по порядку как написано в коде и ТОЛЬКО В САМОМ КОНЦЕ Отработает конструктор. У вас наверное щяс будет вопрос но почему сразу все не статик начинает отрабатывать а я вам отвечу - потому что мы создали и каждый раз когда мы создаем обьект все не статик начинает создаваться точно таким же образом как я написал чуть выше и ЭТО БУДЕТ ПРИ КАЖДОМ СОЗДАНИИ ОБЬЕКТА!!!! Но главное запомнить все статик поля иницализируются 1 единственный раз при обращении к классу а дальше уже значения статик полей подменяется на значения которые мы ему дадим при повторном обращении к классу.ВОТ. А с наследованием таже самая логика: Сначала все у родителя А только потом все у потомка!!!!! Надеюсь понятно обьяснил😅😅
Александр Уровень 23
8 января 2025
Два раза прочел. Ничего не понял и пошел читать третий раз
Сергей Титов Уровень 1
29 февраля 2024
Нормально всё описано. Тут больше и не скажешь. Зато если это всё исполнить через отладчик, пошагово, то всё на свои места становится. Если вообще тяжко, распечатываем всё на листиках склеиваем, рисуем стрелочки откуда что взялось. Сделал так и этак, ощутил кипение мозга,чашечка кофе - и озарение!😅
Andrzej Уровень 32 Expert
11 ноября 2023
Тот случай, когда лекцию лучше переписать, а что бы понять - лучше поискать на других ресурсах. Таких мест пока на курсе почти не было, но это - именно такое. Огромный громоздкий кусок кода с минимальными пояснениями - явно не лучший вариант объяснения.
sTra1cs Уровень 24
6 ноября 2023
Подскажите плиз: Каким образов при вызове из метода мейн ->MyClass.print() - вызывается все что указано в примере ? Как это работает ?
Виктор Ш Уровень 72
14 апреля 2025
В Java, когда ты впервые обращаешься к классу, например: MyClass.print(); — JVM загружает класс в память. И в момент загрузки происходят следующие шаги: Что выполняется при первом обращении к классу: Выполняются статические блоки static {} — в порядке их объявления Инициализируются статические поля Только после этого выполняется то, что ты попросил — print()
Vitalii Уровень 13 Expert
2 августа 2023
Очень громоздкий кусок кода для понимания. Вобщем, только запутывает, а не проясняет (
Андрей Уровень 101 Expert
10 сентября 2022
Про блок инициализации уже была лекция? Первый раз вижу это понятие.
Екатерина Уровень 70 Expert
2 августа 2022
Непонятна идея материала, нет value, по крайней мере в данный момент) Возможно будет понятно дальше но сейчас этот текст воспринимается как рыбка за стеклом булькает)) И меня одну смущает метод без имени но статичный?) Я видимо чтото упустила по лекциям. По сути гугл мне сказал проще, запомню пока как данность) Когда в классе присутствуют все три метода инициализации (конструкторы, нестатические блоки инициализации и статические блоки инициализации), статические всегда выполняются первыми (когда класс загружается в память) в порядке их объявления, затем выполняются нестатические блоки инициализации в порядке, в котором они объявлены, а после них – конструкторы. источник - https://habr.com/ru/post/480544/
Артемий Уровень 26
24 апреля 2022
Это логично.
Павел Уровень 28
23 января 2022
У Брюса Эккеля Философия Java (4-е издание) это неплохо описано.
Andrei Уровень 34
1 апреля 2022
какой год?