Что такое инициализационные блоки в Java и какие они бывают?

Ответ

Инициализационные блоки в Java — это блоки кода без имени, выполняемые для инициализации полей класса. Они бывают двух видов: статические и нестатические.

1. Нестатический блок инициализации

  • Выполняется перед каждым вызовом конструктора при создании объекта.
  • Используется для инициализации нестатических полей сложной логикой.
  • В одном классе может быть несколько блоков — они выполняются в порядке объявления.
public class MyClass {
    private int x;
    private List<String> list;

    // Нестатический блок
    {
        x = 10;
        list = new ArrayList<>();
        list.add("First"); // Сложная логика инициализации
        System.out.println("Нестатический блок выполнен. x = " + x);
    }

    public MyClass() {
        System.out.println("Конструктор выполнен.");
    }
}
// Вывод при new MyClass():
// Нестатический блок выполнен. x = 10
// Конструктор выполнен.

2. Статический блок инициализации

  • Выполняется один раз при первой загрузке класса в JVM (перед созданием любого объекта или обращением к статическим членам).
  • Используется для инициализации статических полей сложной логикой.
public class DatabaseConfig {
    private static Properties config;

    // Статический блок
    static {
        config = new Properties();
        try (InputStream is = DatabaseConfig.class.getResourceAsStream("/db.properties")) {
            config.load(is); // Загрузка конфигурации из файла
            System.out.println("Статический блок: конфиг загружен.");
        } catch (IOException e) {
            throw new RuntimeException("Ошибка загрузки конфига", e);
        }
    }

    public static String getUrl() {
        return config.getProperty("db.url");
    }
}

Порядок выполнения инициализации:

  1. Статические поля и блоки класса (в порядке объявления).
  2. Нестатические поля и блоки объекта (в порядке объявления).
  3. Конструктор объекта.

Ответ 18+ 🔞

А, инициализационные блоки, ёпта! Это ж как те самые закулисные рабочие, которые всё подготавливают, пока актёры-конструкторы на сцену не вышли. Суть проще пареной репы, но народ иногда путается, будто в тёмной комнате ищет чёрную кошку, которой там нет.

Смотри, их всего два вида, и они как близнецы, но один — статик, вечный и одинокий, а второй — нестатик, шустрый и плодовитый.

Первый тип — нестатический блок инициализации.
Этот пацан работает на каждый новый объект, прям как заведённый. Создаёшь ты новый экземпляр — а он уже тут как тут, выскакивает прямо перед конструктором и начинает свою магию. Идеален, когда тебе надо не просто x = 5; присвоить, а там список накрутить, файл прочитать или ещё какую хитрожопую логику для полей запилить. Таких блоков можешь наставить несколько — отработают они строго по очереди, как в очереди за блатными пайками.

public class МояХата {
    private int водка;
    private List<String> закуски;

    // Вот он, нестатический блок
    {
        водка = 100; // грамм, ясное дело
        закуски = new ArrayList<>();
        закуски.add("Селедочка"); // Сложная жизненная инициализация
        System.out.println("Нестатический блок: водка налита, закуска готова. Водка = " + водка);
    }

    public МояХата() {
        System.out.println("Конструктор: можно садиться жрать.");
    }
}
// Создаём объект (new МояХата()) и видим:
// Нестатический блок: водка налита, закуска готова. Водка = 100
// Конструктор: можно садиться жрать.

Второй тип — статический блок инициализации.
А вот это уже серьёзный дядька. Он выполняется всего один раз, когда класс грузится в память, и всё. До первого объекта, до первого статического вызова — он уже всё сделал. Типичное применение — загрузка конфигов, установка драйверов, всё такое глобальное и тяжёлое. Сделал и забыл, как страшный сон.

public class КонфигБазы {
    private static Properties настройки;

    // Статический блок, один на всю жизнь класса
    static {
        настройки = new Properties();
        try (InputStream is = КонфигБазы.class.getResourceAsStream("/db.properties")) {
            настройки.load(is); // Тянем конфиг из файла
            System.out.println("Статический блок: конфиг загружен, можно работать.");
        } catch (IOException e) {
            throw new RuntimeException("Ошибка загрузки конфига, всё пропало!", e);
        }
    }

    public static String getUrl() {
        return настройки.getProperty("db.url");
    }
}

А теперь, блядь, порядок, чтобы не было каши в голове:

  1. Сначала статика. Все статические поля и блоки класса — раз и навсегда, по очереди.
  2. Потом экземпляр. Для каждого нового объекта — все его нестатические поля и блоки, тоже по порядку.
  3. И только в конце, как вишенка на торте, вызывается конструктор объекта.

Вот и вся философия. Не перепутай, а то получится как в той поговорке: статику в конструктор, нестатику в статик — и будет тебе, сука, NullPointerException вместо ужина.