Почему вы можете получить доступ к статическому полю до его определения с помощью метода в Java?
У меня возникла интересная вещь:
static {
System.out.println(test); // error cannot reference a field before it is defined
System.out.println(cheat()); // OK!
}
private static boolean cheat() {
return test;
}
private static boolean test = true;
public static void main(String args[]) {}
Первый способ неправильный, и ваш компилятор и IDE скажут вам это неправильно. Во втором случае обман в порядке, но на самом деле по умолчанию поле test
равно false
. Использование Sun JDK 6.
Ответы
Ответ 1
Это определено в JLS 8.3.2.3. В частности:
Объявление элемента должно появляться текстовым образом перед его использованием [...], если использование происходит в статическом инициализаторе [...] C.
Когда вы вызываете cheat()
, вы обходите это правило. Это фактически пятый пример в список примеров этого раздела.
Обратите внимание, что cheat()
возвращает false в статическом блоке инициализатора, потому что test
еще не инициализирован.
Ответ 2
Так как загрузка классов работает в следующем порядке:
- Loads Определение класса (методы, подписи)
- Выделяет память для ссылок на статические переменные (для
test
) - еще не инициализируется
- Выполняет инициализаторы
static
(для переменных) и блоки static
- для того, чтобы они были определены
Итак, к тому времени, когда вы достигнете блока static
, у вас есть определение метода готово, но у него нет готовой переменной. С cheat()
вы действительно читаете неинициализированное значение.
Ответ 3
Это общие шаги, по которым происходит загрузка классов.
- Загрузка - загрузка класса в память
- Проверка - проверяет двоичное представление класса e правильно
- Подготовка - создайте статические поля для класса и инициализируйте эти поля стандартными значениями по умолчанию.
- Инициализация - вызовет статические инициализаторы и инициализаторы для статических полей
После подготовки ваш тест будет ложным. Затем, прежде чем назначить статическую переменную в значение true, ваш статический блок будет выполнен. Вот почему вы получаете false.
Попробуйте сделать свою статическую переменную окончательной. В этом случае вы получите правду. Это связано с тем, что ваш компилятор будет вставлять значение в байт-код (поскольку поле является окончательным) в качестве части оптимизации