Найти в Дзене
Записки о Java

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

Один из часто задаваемых вопросов новичков (и даже опытных разработчиков) — когда именно выполняется инициализация статических полей и static блоков в Java? Интуитивно может показаться, что это происходит сразу при запуске программы или при первом упоминании класса. Но на самом деле всё немного тоньше — и связано с работой ClassLoader'а и инициализацией класса. Важно разделять два этапа: Согласно Java Language Specification (JLS §12.4), инициализация класса запускается в следующих случаях: ⚠️ Обратите внимание: чтение static final константы, известных на этапе компиляции (например, public static final int X = 42), не вызывает инициализацию класса. Рассмотрим простой пример: Теперь вызовем из другого класса: Вывод: Before accessing class Static block executed initValue() called Value: 100 Как видите — статический блок и метод initValue() выполнились только в момент первого обращения к полю value, а не раньше. Если в классе есть несколько статических полей и блоков, они инициализируются
Оглавление

Введение

Один из часто задаваемых вопросов новичков (и даже опытных разработчиков) — когда именно выполняется инициализация статических полей и static блоков в Java? Интуитивно может показаться, что это происходит сразу при запуске программы или при первом упоминании класса. Но на самом деле всё немного тоньше — и связано с работой ClassLoader'а и инициализацией класса.

Загрузка vs инициализация класса

Важно разделять два этапа:

  1. Загрузка класса (loading) — JVM загружает байт-код класса в память с помощью ClassLoader. На этом этапе статические блоки и переменные ещё не инициализируются.
  2. Инициализация класса (initialization) — JVM выполняет инициализацию статических полей и static {} блоков. Этот этап происходит только тогда, когда класс действительно "используется" впервые.

Согласно Java Language Specification (JLS §12.4), инициализация класса запускается в следующих случаях:

  • Создание экземпляра класса (new MyClass());
  • Вызов статического метода класса;
  • Чтение или запись неконстантного статического поля;
  • Использование отражения (Class.forName() и т.п.);
  • Если это точка входа программы (main).
⚠️ Обратите внимание: чтение static final константы, известных на этапе компиляции (например, public static final int X = 42), не вызывает инициализацию класса.

Пример

Рассмотрим простой пример:

Рисунок: пример
Рисунок: пример

Теперь вызовем из другого класса:

Рисунок: вызов класса StaticInitDemo
Рисунок: вызов класса StaticInitDemo

Вывод:

Before accessing class

Static block executed

initValue() called

Value: 100

Как видите — статический блок и метод initValue() выполнились только в момент первого обращения к полю value, а не раньше.

Порядок инициализации

Если в классе есть несколько статических полей и блоков, они инициализируются в порядке их объявления в исходном коде:

Рисунок: порядок инициализации
Рисунок: порядок инициализации

Вывод при первом использовании класса:

Block 1

Init a

Block 2

Init b

Заключение

  • static блоки и статические поля инициализируются не при загрузке класса, а при его инициализации.
  • Инициализация происходит лениво — только когда класс "реально используется" впервые.
  • Порядок инициализации строго следует тексту класса.
  • Чтение компиляционных констант (static final, известных на этапе компиляции) не вызывает инициализацию.

Это поведение важно учитывать при проектировании классов с тяжёлой статической инициализацией — особенно в многопоточной среде или при использовании reflection.