Я нашел ошибку в Java Puzzlers VI - может кто-нибудь объяснить это?
Взгляните на это java puzzles vid от Джоша Блоха и Уильяма Пью, со временем индекс 0: 25: 00-0: 33: 00.
Один из динамиков говорит, что если вы используете строчный boolean
вместо boolean
, тогда LIVING
будет рассматриваться как истинная "константа времени компиляции", и это уже не имеет значения, когда оно инициализируется.
Ну, это все прекрасно и денди, но посмотрите, что произойдет, когда вы вернетесь к первоначальному порядку между статическим init и конструктором, а затем выполните его с помощью простой операции "Извлечь метод". Эти две программы печатают разные выходы:
public class Elvis {
private static final Elvis ELVIS = new Elvis();
private Elvis () {}
private static final boolean LIVING = true;
private final boolean alive = LIVING;
private final boolean lives () {return alive;}
public static void main(String[] args) {
System.out.println(ELVIS.lives()); // prints true
}
}
И с рефакторизованным returnTrue()
методом
public class Elvis {
private static final Elvis ELVIS = new Elvis();
private Elvis () {}
private static final boolean LIVING = returnTrue();
private static boolean returnTrue() {
return true;
}
private final boolean alive = LIVING;
private final boolean lives () {return alive;}
public static void main(String[] args) {
System.out.println(ELVIS.lives()); // prints false
}
}
Почему извлечение метода returnTrue() изменяет вывод программы в этом случае?
Ответы
Ответ 1
Ключом к поведению, которое вы наблюдаете, является понятие "постоянная переменная". Этот оксюморон определяется в JLS 4.12.4 как переменная примитивного типа или типа String, которая является окончательной и инициализируется выражением постоянной времени компиляции. В JLS 13.1 говорится, что ссылки на постоянные поля разрешаются во время компиляции с постоянными значениями, которые они обозначают (т.е. Они встроены). Головоломка в видео полагается на то, что булеан не является ни примитивным, ни строковым. Ваш вариант основан на том факте, что вызов метода (returnTrue) в выражении не позволяет ему быть постоянным выражением времени компиляции. В любом случае, LIVING не является постоянной переменной, и программа отображает противоречивое поведение.
Головоломка 93 в Java Puzzlers ( "Class Warfare" ) связана и даже более удивительна.
Ответ 2
Во втором случае LIVING
инициализируется выражением времени выполнения, поэтому он больше не является константой времени компиляции, а его значение false
в момент построения ELVIS
.