Java: доступ к константам в перечислении (enum)
прочитав книгу SCJP, я нашел что-то подобное в главе 1 "Самодиагностика":
enum Animals {
DOG("woof"), CAT("meow"), FISH("burble");
String sound;
Animals(String s) { sound = s; }
}
class TestEnum {
static Animals a;
public static void main(String[] args) {
System.out.println(a.DOG.sound + " " + a.FISH.sound);
// the following line is from me
System.out.println(Animals.DOG.sound + " " + Animals.FISH.sound);
}
}
Примечание: код компилируется отлично.
Я не понимаю, почему мы можем получить доступ к константам DOG, CAT или FISH из переменной a
. Я думал (и это также написано в книге), что константы DOG, FISH, CAT выполняются так же, как public static final Animals DOG = new Animals(1);
Так что, если они действительно статичны, почему мы можем получить к ним доступ из a
?
Последняя строка - это то, с чем я знаком.
Ответы
Ответ 1
Запись a.DOG
совпадает с записью Animal.DOG
. То есть компилятор заменит переменную своим типом времени компиляции Animal. Это считается плохим кодом, поскольку он скрывает тот факт, что он использует тип времени компиляции вместо динамического типа a
.
Ответ 2
Хотя это работает, не делайте этого так. Используйте перечисления с Animal.DOG
, Animal.CAT
и т.д.
То, что указано выше, объявляет объект типа перечисления и ссылается на статический DOG
на нем. Компилятор знает тип a
и знает, что вы хотите Animal.DOG
. Но это убивает читаемость.
Я считаю, что целью этого является сокращение использования перечислений. a.DOG
вместо Animal.DOG
. Если вы действительно хотите сократить его, вы можете использовать import static fqn.of.Animal
, а затем просто использовать DOG
.
Ответ 3
Вы можете получить доступ к статистике из экземпляра, но это действительно плохой вкус, поскольку статика не так привязана к экземпляру, связанному с классом.
Как бы ни говорила книга, не используйте статику таким образом. И если вы запустите checkstyle и тому подобное, они предупреждают об этом:)
BTW a является нулевым в вашем примере. Он инициализируется где-то?
ИЗМЕНИТЬ
Я знаю, что компилятор знает, к чему привязан a.DOG, поскольку статика не может быть переопределена. Это не нужно, чтобы определить вызов, только тип времени компиляции a, который он имеет.
Я также знаю, что пример работает, даже если a имеет значение null (я попробовал, чтобы я знал:).
Но я все еще думаю, что это странно, вы можете получить материал от нуля. И это запутывает:
Animals a = null;
System.out.println(a.DOG); // OK
a.doSomething(); // NullPointerException
Когда я буду отлаживать NPE, я бы предположил, что a не может быть пустым, поскольку println работал нормально. Смешение.
Хорошо, Java. Если вы думаете, что видели все это, вы снова получаете что-то еще:)