Мне интересно, когда статические переменные инициализируются значениями по умолчанию. Верно ли, что при загрузке класса создаются (выделяются) статические переменные, затем выполняются статические инициализаторы и инициализации в объявлениях? В какой момент приводятся значения по умолчанию? Это приводит к проблеме прямой ссылки.
Также, пожалуйста, можете ли вы объяснить это со ссылкой на вопрос, заданный Почему статические поля не инициализируются вовремя? и особенно ответ, данный Кевином Броком на том же сайте. Я не могу понять третий пункт.
java
static
initialization
Анкит
источник
источник
Ответы:
Из См. Методы статических переменных Java :
Переменные экземпляра и класса (статические) автоматически инициализируются стандартными значениями по умолчанию, если вы не можете преднамеренно инициализировать их. Хотя локальные переменные не инициализируются автоматически, вы не можете скомпилировать программу, которая не может инициализировать локальную переменную или присвоить значение этой локальной переменной до ее использования.
На самом деле компилятор создает внутреннюю процедуру инициализации одного класса, которая объединяет все инициализаторы статических переменных и все блоки кода статического инициализатора в том порядке, в котором они указаны в объявлении класса. Эта единственная процедура инициализации запускается автоматически, только один раз, при первой загрузке класса.
В случае внутренних классов у них не может быть статических полей
См. JLS 8.1.3 Внутренние классы и закрывающие экземпляры
final
Поля в Java могут быть инициализированы отдельно от места их объявления, однако это не может быть применимо кstatic final
полям. См. Пример ниже.final class Demo { private final int x; private static final int z; //must be initialized here. static { z = 10; //It can be initialized here. } public Demo(int x) { this.x=x; //This is possible. //z=15; compiler-error - can not assign a value to a final variable z } }
Это происходит потому , что есть только одна копия из
static
переменных , связанных с типом, а не один , связанным с каждым экземпляром типа , как с переменным экземпляром и если мы попытаемся инициализироватьz
типstatic final
в конструкторе, он будет пытаться повторно инициализироватьstatic final
поле типаz
потому что конструктор запускается при каждой реализации класса, что не должно происходить со статическимиfinal
полями.источник
In case of static inner classes, they can not have static fields
похоже на опечатку. Внутренние классы нестатичны.Увидеть:
Последний, в частности, предоставляет подробные шаги инициализации, которые объясняют, когда инициализируются статические переменные и в каком порядке (с оговоркой, что
final
переменные класса и поля интерфейса, которые являются константами времени компиляции, инициализируются первыми).Я не уверен, какой у вас конкретный вопрос по пункту 3 (если вы имеете в виду вложенный?). В подробной последовательности указано, что это будет рекурсивный запрос инициализации, поэтому он продолжит инициализацию.
источник
Статические поля инициализируются, когда класс загружается загрузчиком классов. В это время присваиваются значения по умолчанию. Это делается в том порядке, в котором они указаны в исходном коде.
источник
Порядок инициализации:
Детали процесса объяснены в документе спецификации JVM .
источник
статическая переменная
источник
Начиная с кода из другого вопроса:
class MyClass { private static MyClass myClass = new MyClass(); private static final Object obj = new Object(); public MyClass() { System.out.println(obj); // will print null once } }
Ссылка на этот класс запустит инициализацию. Сначала класс будет помечен как инициализированный. Затем первое статическое поле будет инициализировано новым экземпляром MyClass (). Обратите внимание, что myClass сразу получает ссылку на пустой экземпляр MyClass. Пробел есть, но все значения равны нулю. Конструктор теперь выполняется и печатает
obj
, что равно нулю.Теперь вернемся к инициализации класса:
obj
делается ссылка на новый реальный объект, и все готово.Если это было установлено таким оператором, как:
MyClass mc = new MyClass();
пространство для нового экземпляра MyClass снова выделяется (и ссылка помещается вmc
). Конструктор снова выполняется и снова печатаетobj
, который теперь не равен нулю.Настоящая уловка здесь в том, что когда вы используете
new
, as inWhatEverItIs weii = new WhatEverItIs( p1, p2 );
weii
сразу получает ссылку на немного обнуленной памяти. Затем JVM перейдет к инициализации значений и выполнению конструктора. Но если вы каким-то образом ссылаетесьweii
до этого - например, ссылаясь на него из другого потока или или путем ссылки из инициализации класса - вы смотрите на экземпляр класса, заполненный нулевыми значениями.источник
Статическая переменная может быть инициализирована следующими тремя способами: выберите любой, который вам нравится.
или вы можете сделать статический блок, например:
static { // whatever code is needed for initialization goes here }
Есть альтернатива статическим блокам - вы можете написать приватный статический метод
class name { public static varType myVar = initializeVar(); private static varType initializeVar() { // initialization code goes here } }
источник