Ответ 1
Сводка: оба инициализатора получают доступ к полю, которое еще не инициализировано (и, следовательно, по-прежнему имеет значение по умолчанию, равное нулю). Поскольку это, скорее всего, ошибка программирования, язык запрещает некоторые простые формы такого доступа. Однако это не запрещает более сложную форму.
Поведение совместимо с JLS, в частности §8.3.2.3. Ограничения на использование полей во время инициализации
Объявление элемента должно отображаться текстовым образом до его использования, только если элемент является экземпляром (соответственно
static
) поля класса или интерфейсаC
и выполняются все следующие условия:
Использование происходит в инициализаторе инициализатора экземпляра экземпляра (соответственно
static
) C или в экземпляре (соответственноstatic
).Использование не находится в левой части задания.
Использование осуществляется с помощью простого имени.
C
- самый внутренний класс или интерфейс, охватывающий использование.
Первый пример удовлетворяет всем четырем условиям и поэтому недействителен. Второй пример не удовлетворяет третьему условию (this.x
- не простое имя), и поэтому он ОК.
Общая последовательность событий следующая:
- Когда экземпляр класса создается, все поля инициализируются значениями по умолчанию их типа.
- Инициализаторы затем выполняются в текстовом порядке (сверху вниз).
Таким образом, если инициализатор ссылается на поле, которое появляется позже в определении класса (или в самом поле), оно увидит значение по умолчанию этого другого поля. Вероятно, это будет ошибка программирования и поэтому явно запрещена в §8.3.2.3.
Если вы обходите §8.3.2.3, например, используя this.
для пересылки в поле, вы увидите значение по умолчанию (ноль для int
). Таким образом, четко определено и гарантировано установить x
на 42
:
class test {
int x = this.x + 42;
}