Ответ 1
Специализированный enum
- это не что иное, как подкласс с семантикой внутреннего класса. Если вы посмотрите на байтовый код после компиляции, вы заметите, что компилятор только вставляет метод accessor для чтения частного поля, но любое специализированное перечисление компилируется как собственный класс. Вы можете думать о своем enum
как реализованном как:
public abstract class MyEnum {
private static class First extends MyEnum {
@Override
public String doIt() {
return "1: " + someField; //error
}
}
private static class Second extends MyEnum {
@Override
public String doIt() {
return "2: " + someField; //error
}
}
public static final MyEnum FIRST = new First();
public static final MyEnum SECOND = new Second();
private String someField;
public abstract String doIt();
}
Как вы можете видеть, происходят одни и те же ошибки компилятора. Эффективно ваша проблема не связана с enum
, а с их семантикой внутреннего класса.
Однако вы обнаружили пограничный случай, когда компилятор угадывал намерение вашего кода и пытался предупредить вас о том, что то, что вы намереваетесь, является незаконным. В общем поле someField
видно любому специализированному enum
. Однако есть два способа доступа к полю private
из внутреннего класса, и только один из них является законным:
-
private
члены не наследуются. Поэтому вы не можете получить доступ к полюprivate
из экземпляраthis
, когда он был определен в суперклассе. -
Для внутренних классов члены внешних классов доступны, даже если они
private
. Это достигается компилятором, вставляя методы доступа к внешним классам, которые раскрывают поляprivate
с помощью методов доступа. Поле nonstatic
может быть доступно только в том случае, если внутренний класс не являетсяstatic
. Однако дляenum
s внутренние классы всегдаstatic
.
Более поздним условием является то, о чем компилятор жалуется:
Невозможно сделать статическую ссылку на нестатическое поле
someField
Вы пытаетесь получить доступ к полю не static
из внутреннего класса static
. Это невозможно, даже если поле будет технически видимым из-за внутренней семантики класса. Вы можете дать указание компилятору явно получить доступ к значению, прочитав его из супер-класса, например:
public String doIt() {
MyEnum thiz = this;
return thiz.someField;
}
Теперь компилятор знает, что вы пытаетесь получить доступ к элементу видимого (внешнего) типа вместо ошибочного доступа к полю someField
(нестатического) экземпляра внешнего класса (которого не существует). (Точно так же вы можете написать super.someField
, который выражает ту же идею, что вы хотите спуститься по цепочке наследования и не получить доступ к внешнему полю экземпляра.) Более простым решением было бы просто создать поле protected
. Таким образом, компилятор рад видеть видимость наследования и компилирует исходную настройку.