Переменные экземпляра и класса (статические) автоматически инициализируются стандартными значениями по умолчанию, если вы не можете их инициализировать намеренно. Локальные переменные не инициализируются автоматически, вы не можете скомпилировать программу, которая не инициализирует локальную переменную или не присваивает значение этой локальной переменной перед ее использованием.

Что на самом деле делает компилятор, так это внутренне создает процедуру инициализации одного класса, которая объединяет все статические переменные и все статические блоки кода в том порядке, в котором они появляются в объявлении класса. Эта единственная процедура инициализации запускается автоматически только один раз при первой загрузке класса.

Посмотрите на этот первый пример:

Когда вы запустите его, вы получите вывод:

A Loaded
A should have been loaded
A1 should not have been loaded
A1 Loaded
10

Сначала загружается, поскольку вы используете его основной метод. Даже если вы выполняете A1 a1 = null;, A1 не будет загружен, поскольку он еще не используется (поэтому JVM определяет, что ей еще не нужно его загружать). Когда вы выполняете a1.i, вы используете A1 , поэтому перед использованием его необходимо загрузить. Это когда A1 загружается. Наконец напечатано 10.

Посмотрите на этот последний код и комментарии:

Когда вы запустите его, вы получите вывод:

Value of var1 = 0
Object 1
Value of var1 = 1
Value of var2 = 0
Object 2
Value of var1 = 2
Value of var2 = 0
Value of var1 = 3
Value of var2 = 1
Value of var1 = 4
Value of var2 = 1

Целью предыдущего кода является проверка поведения статических переменных и переменных экземпляра, когда у нас есть конструкторы и другие методы, изменяющие свои значения.

Для получения дополнительной информации взгляните на официальную документацию: