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. Если вы думаете, что видели все это, вы снова получаете что-то еще:)