Почему мы разрешаем ссылаться на член перечисления члена перечисления на Java?
Учитывая следующее перечисление:
enum Repeat {
Daily,
Weekly,
Yearly
}
Я понимаю, что мы можем написать так:
Repeat repeat = Repeat.Daily.Weekly.Yearly.Weekly;
что эквивалентно:
Repeat repeat = Repeat.Weekly;
Могу ли я узнать, почему такой синтаксис разрешен? Есть ли способ, чтобы компилятор предупреждал нас об этом?
Ответы
Ответ 1
Это разрешено, поскольку Daily, Weekly, Yearly
являются static
полем по default
внутри enum
и содержат объект Repeat
. Кроме того, вы получите предупреждение от компилятора "The static field Repeat.Weekly should be accessed in a static way"
. Он похож на приведенные ниже строки кода.
class Foo{
public static Foo obj1 = new Foo();
public static Foo obj2 = new Foo();
public static Foo obj3 = new Foo();
}
Foo f = Foo.obj1.obj2.obj3; // will work fine but you will get a warning from the compiler.
Вот некоторая часть проверки байт-кода для перечисления Repeat
и из этого ясно, что переменная Enum
является static
и содержит объект Object Enum.
0: new #1 // class com/java8/demo/Repeat
3: dup
4: ldc #14 // String Daily
6: iconst_0
7: invokespecial #15 // Method "<init>":(Ljava/lang/String;I)V
10: putstatic #19 // Field Daily:Lcom/java8/demo/Repeat;
13: new #1 // class com/java8/demo/Repeat
Ответ 2
Экземпл Enum - это только static
экземпляр класса enum.
У нас есть два способа доступа к статическому полю класса:
- Через класс itelft: Repeat.Daily
- Через экземпляр класса: Repeat.Daily.Daily
Когда вы связываете перечисление:
Repeat repeat = Repeat.Daily.Weekly.Yearly.Weekly;
Это похоже на получение статического поля из экземпляра класса.
Ответ 3
Есть ли способ заставить компилятор предупредить нас об этом?
Да, используйте хорошую среду IDE и включите предупреждение. Таким образом, вы будете уведомлены, как только напишите код, прежде чем вы его скомпилируете.
Например, в Eclipse он называется "Нестатический доступ к статическому элементу":
Ответ 4
Литералы Enum являются статическими членами, и каждый статический член может получить к ним доступ либо с помощью ссылки на класс:
TypeName.staticMember
TypeName.staticMethod()
Или на примере:
new TypeName().staticMember
new TypeName().staticMethod()
Второй подход не рекомендуется (и компилятор выдаст предупреждение)
Поскольку перечисляемые литералы являются только статическими членами, Repeat.Daily.Weekly.Yearly.Weekly
похож на второй фрагмент кода выше, обращаясь к статическим членам в ссылках на экземпляры.
С классом это будет:
class Type {
static Type INSTANCE1, INSTANCE2, INSTANCE3;
}
И можно получить ссылку на INSTANCE3
используя Type.INSTANCE1.INSTANCE2.INSTANCE3
. Это действительно, но это плохая практика.