2012-03-12 2 views
10

У меня проблема с пониманием порядка, в котором происходит инициализация. это порядок я предположил:В каком порядке выполняются блок инициализации и определения переменных и т. Д.? (в 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. 
     } 
    } 

я могу 't выяснить, почему нет ошибки на

b=0; 
+0

Какой у вас компилятор? Оракул Джавак? Или некоторые IDE (по крайней мере Eclipse приносит свой собственный компилятор) –

+0

Eclipse и Oracles javac ведет себя одинаково в этом сценарии. – aioobe

+1

с использованием eclipse .. – Untitled

ответ

4

Спецификация языка Java (раздел 8.3.2.3) говорит, что вы можете использовать переменную слева стороны назначения, то есть назначить ему, прежде чем он будет объявлен, но вы не сможете использовать его с правой стороны.

Все переменные инициализируются значениями по умолчанию, затем явные инициализаторы и анонимные блоки запускаются в порядке их нахождения в исходном файле. Наконец, вызывается конструктор.

Статика работает только один раз при первом использовании класса.

Ошибка компиляции, похоже, является правилом Java, а не чем-то, что обязательно имеет смысл в каждом случае.

+0

последующий вопрос: ok. Теперь я понимаю ситуацию здесь. просто не могу понять, почему существует такая особенность. Я не могу себе представить, как это использовать.почему кто-то хочет назначить переменную в блоке инициализации перед ее объявлением? почему бы просто не объявить это первым? – Untitled

+1

Я согласен, и почему мы можем назначить ему значение, но не считать его? JLS говорит, что все переменные создаются и инициализируются значениями по умолчанию, прежде чем запускается какой-либо явный код, поэтому переменная существует и имеет значение, которое мы просто не можем прочитать. Мне это кажется странным. –

+0

Это сделано, чтобы избежать круговых ссылок. Например. int a = b + 1; int b = a + 2; – ekaerovets

1

Прежде всего, ваши предположения более или менее правильны, за исключением того факта, что объявления (с инициализацией, такие как int b = 0) и блоки инициализатора экземпляра выполняются в том порядке, в котором они записаны.

int b = 0; // executed first 

{ 
    b = 1; // executed second 
} 

int a = b; // executed third 

отметить также, что декларация т.е. int b не выполняется . В объявлении объявляется существование переменной.

Что касается полученной вами ошибки (или, скорее, ошибки вы не сделали) Я согласен, что это выглядит странно. Я предполагаю, что компилятор имеет дело с ссылкой на переменную в выражении и присвоением ей значения по-разному. При записи в переменную в инициализаторе экземпляра он просто проверяет, есть ли переменная, а при чтении из нее требуется, чтобы она была объявлена ​​над блоком инициализатора экземпляра. Я посмотрю, смогу ли я найти ссылку для этого в JLS.

3

Переменные определения не выполняются «до» блоков. Они оба сделали в то же время, в том порядке, что они определены

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 
+1

Правильно, но вопрос, почему он может писать переменную, объявленную ниже строки, но не прочитанную из той же переменной, не отвечает. – aioobe