Точные правила, управляющие прямой ссылкой на переменные класса, описаны в разделе §8.3.2.3 JLS:
8.3.2.3 Ограничения на использование полей при инициализации
Декларация члена должна
появляются в тексте перед использованием
только если член является экземпляром
(соответственно static
) поле класса
или интерфейс C и все
выполняются следующие условия:
- Использование происходит в экземпляре (соответственно
static
) переменной
инициализатор C или в экземпляре
(соответственно static
) инициализатор
C.
- Использование не в левой части назначения.
- Использование через простое имя.
- C является самым внутренним классом или интерфейсом, включающим использование.
Ошибка времени компиляции происходит, если любой из
четыре вышеуказанных требования не являются
мет.
Это означает, что ошибка во время компиляции
Результаты тестовой программы:
class Test {
int i = j; // compile-time error: incorrect forward reference
int j = 1;
}
тогда как следующий пример компилируется
без ошибок:
class Test {
Test() { k = 2; }
int j = 1;
int i = j;
int k;
}
хотя конструктор
(§8.8) для теста относится к
поле к, которое объявлено три строки
позже.
Эти ограничения предназначены для
поймать, во время компиляции, круговой или
иначе искаженные инициализации.
Таким образом, оба:
class Z {
static int i = j + 2;
static int j = 4;
}
и
class Z {
static { i = j + 2; }
static int i, j;
static { j = 4; }
}
приводит к ошибкам во время компиляции.
Доступ по методам не проверяется в
вот так вот:
class Z {
static int peek() { return j; }
static int i = peek();
static int j = 1;
}
class Test {
public static void main(String[] args) {
System.out.println(Z.i);
}
}
производит вывод:
0
потому что инициализатор переменной для i
использует метод класса Peek для доступа
значение переменной j перед j
был инициализирован его переменной
инициализатор, в этот момент он еще
имеет значение по умолчанию (§4.12.5) .