Прямое перечисление против перечисления .. В чем заключается точная техническая разница?

#java #enums

Вопрос:

Учитывая следующее перечисление:

 public enum Letter {
    Alpha, Beta, Gamma, Delta;
}
 

Затем оба следующих действия компилируются без ошибок:

 Letter       letter1 = Letter.Alpha;
Enum<Letter> letter2 = Letter.Beta;
 

Вызов getClass() или name() или ordinal() на обоих letter1 и letter2 показывает одни и те же результаты.

Но! Следующее будет скомпилировано:

 switch( letter1 ) {
case Alpha:
case Beta:
}
 

Пока этого не будет:

 switch( letter2 ) {
case Alpha:
case Beta:
}
 

Так в чем же, если таковые имеются, заключается точная техническая разница между этими двумя переменными?

Комментарии:

1. Оказывается, что из-за ограничительного типа bound ( T extends Enum<T> ) единственным классом, который может быть реализован Enum<Letter> , является Letter он сам. Но система типов этого не знает, поэтому она не делает вывод, что набор значений Enum<Letter> состоит только из констант Letter и ничего больше. В общем, вы очень редко используете Enum напрямую, кроме как в качестве привязки к типу. (Мало чем отличается AbstractList ; почти единственные места, где он используется, — это extends предложения его подклассов.)

2. @Zabuzard Нет, это не так. Это базовый класс Letter , вот так просто. Вот почему назначение возможно, но случаи переключения-нет.

Ответ №1:

Letter это Enum<Letter> так, как Integer есть Number . Подкласс к суперклассу. Единственная разница в том, что Enum<> это привилегированный суперкласс, связанный с определенной функцией языка. (Смотрите java.lang.Record еще один такой привилегированный суперкласс.)

Если у нас есть эти две переменные:

 Integer n1 = 1;
Number  n2 = 2;
 

… тогда это работает:

 jshell> switch(n1) { case 1: System.out.println("one"); break; default: System.out.println("not one"); break;}
one
 

… но это не значит:

 jshell> switch(n2) { case 1: System.out.println("one"); break; default: System.out.println("not one"); break;}
|  Error:
|  incompatible types: java.lang.Number cannot be converted to int
|  switch(n2) { case 1: System.out.println("one"); break; default: System.out.println("not one"); break;}
|        ^--^
 

В обоих случаях компилятор не может доказать (до выполнения), что Number или Enum<Letter> является чем-то, что он может включить, поэтому он не позволит вам этого сделать.