В каком порядке выполняются блокировка инициализатора и определения переменных и т.д.? (в java)
У меня проблема с пониманием порядка, в котором происходит инициализация. это тот порядок, который я предполагал:
*Once per
1. Static variable declaration
2. Static block
*Once per object
3. variable declaration
4. initialization block
5. constructor
но в соответствии с этим кодом я, очевидно, ошибаюсь:
class SomethingWrongWithMe
{
{
b=0; //no. no error here.
int a = b; //Error: Cannot reference a field before it is defined.
}
int b = 0;
}
И ошибка исчезнет, если я это сделаю:
class SomethingWrongWithMe
{
int b = 0;
{
b=0;
int a = b; //The error is gone.
}
}
Я не могу понять, почему на
b=0;
Ответы
Ответ 1
Спецификация языка Java (раздел 8.3.2.3) говорит, что вы можете использовать переменную в левой части выражения, то есть назначить ей, прежде чем она будет объявлена, но вы не сможете использовать ее с правой стороны.
Все переменные инициализируются значениями по умолчанию, затем явные инициализаторы и анонимные блоки запускаются в том порядке, в котором они находятся в исходном файле. Наконец, вызывается конструктор.
Статики запускаются только один раз при первом использовании класса.
Ошибка компиляции представляется правилом Java, а не тем, что обязательно имеет смысл в каждом случае.
Ответ 2
Переменные определения не выполняются "до" блоков. Они оба выполняются одновременно, в том порядке, в котором они определены.
class SomethingWrongWithMe {
{
b = debug("block 1");
}
int b = debug("define");
{
b = debug("block 2");
}
private int debug(String str) {
System.out.println(str);
return 0;
}
}
Выход
block 1
define
block 2
Ответ 3
Прежде всего, ваши предположения более или менее правильны, за исключением того факта, что объявления (с инициализацией, такие как int b = 0
) и блоки инициализатора экземпляра выполняются в том порядке, в котором они записаны.
int b = 0; // executed first
{
b = 1; // executed second
}
int a = b; // executed third
Также обратите внимание, что объявление, т.е. int b
, не выполняется. Объявление просто объявляет о существовании переменной.
Что касается полученной вами ошибки (или, скорее, ошибки, которую вы не получили), я согласен, что это выглядит странно. Я предполагаю, что компилятор имеет дело с ссылкой на переменную в выражении и присвоением ей значения по-разному. При записи в переменную в инициализаторе экземпляра он просто проверяет, есть ли переменная, а при чтении из нее требуется, чтобы она была объявлена над блоком инициализатора экземпляра. Я посмотрю, могу ли я найти ссылку для этого в JLS.