Мне было интересно, почему, хотя совершенно справедливо сделать следующее в Java
public enum Test {
VALUE1() {
public static final String CONST_RELATED_TO_VALUE1 = "constant";
public static final String OTHER_CONST_RELATED_TO_VALUE1 = "constant";
},
VALUE2() {
public static final String CONST_RELATED_TO_VALUE2 = "constant";
},
VALUE3;
}
доступ к константам, как можно было бы ожидать, используя Test.VALUE1.CONST_RELATED_TO_VALUE1
не работает.
Теперь я понимаю, что VALUE1
, VALUE2
и т.д. на самом деле все обычно рассматриваются как статический окончательный экземпляр типа Test
и, следовательно, не имеют этих полей, но информация должна теоретически доступна во время компиляции, что можно легко проверить, выполнив небольшой тест
// print types and static members
for (Object o: Test.values()) {
System.out.println(o.toString() + ": " + o.getClass());
for (Field field : o.getClass().getDeclaredFields()) {
if (java.lang.reflect.Modifier.isStatic(field.getModifiers())) {
System.out.println("\t" + field);
}
}
}
что приводит к следующему выводу
VALUE1: class Test$1
public static final java.lang.String Test$1.CONST_RELATED_TO_VALUE1
public static final java.lang.String Test$1.OTHER_CONST_RELATED_TO_VALUE1
VALUE2: class Test$2
public static final java.lang.String Test$2.CONST_RELATED_TO_VALUE2
VALUE3: class Test
public static final Test Test.VALUE1
public static final Test Test.VALUE2
public static final Test Test.VALUE3
private static final Test[] Test.$VALUES
Понятно, что у нас есть фактически выделенные подклассы во время выполнения для VALUE1
и VALUE2
. Но это также похоже на то, что мы теряем конкретную информацию о типе VALUE1
и VALUE2
, так как компилятор генерирует значения статического enum для базового класса enum Test
, как используется VALUE3
: все члены имеют тип Test
и конкретные типы отбрасываются.
Однако мне кажется, что если компилятор просто сохранил такие типы
public static final Test$1 Test.VALUE1
public static final Test$2 Test.VALUE2
public static final Test Test.VALUE3
весь окружающий код все равно будет работать. Кроме того, мы могли бы также сделать то, что я попробовал вначале, и получить доступ CONST_RELATED_TO_VALUE1
через Test.VALUE1
, который теперь явно является экземпляром типа Test$1
, а не только Test
, и, хотя его вообще следует избегать, кажется, в этом случае отлично подходит для доступа к этому статическому элементу через экземпляр.
Теперь, как многие люди правильно указали, использование анонимных классов слева недействительно Java-кода и, возможно, также для компилятора не допускается без какого-либо значительного изменения спецификации. Однако это можно было легко решить, используя именованные внутренние классы, поэтому мы имели бы
public static final Test.Value1 Test.VALUE1
public static final Test.Value2 Test.VALUE2
public static final Test Test.VALUE3
Это даже дает дополнительное преимущество для отладки, что имя внутреннего подкласса четко отображает соответствующее значение перечисления.
Теперь я понимаю, что должны были быть некоторые незначительные изменения, но переход от анонимных к именованным классам и не выбрасывание типов кажется небольшим изменением, и это выглядит как довольно приятная функция, без простого способа эмулировать он использует переопределенные элементы или что-то в этом роде.
Итак, мне было интересно, почему это не было реализовано, как за исключением времени? Я пропустил что-то важное здесь, что помешало бы компилятору сделать это (как по сложности реализации, так и по невозможности системы типов), просто ли это не было реализовано, чтобы упростить его, потому что не было времени или что-то в этом направлении?
(Я в основном искал причины, по которым было принято решение реализовать это с точки зрения компилятора/типа, а не для практических альтернатив этому, так как есть определенная пара, хотя она все еще кажется приятной шаблон)