#java #enums
#java #перечисления
Вопрос:
Как я могу получить доступ (без отражения) RAIN
и WIND
поля из какого-либо другого класса? Моя среда разработки показывает ошибки, когда я пытаюсь ссылаться Season.FALL.RAIN
на , Season.FALL.WIND
, и вызывать Season.FALL.getWind()
. Season
enum компилируется нормально:
public enum Season {
WINTER,
SPRING,
SUMMER,
FALL {
public static final String RAIN = "rain";
public final String WIND = "wind";
public String getWIND() {
return WIND;
}
};
}
Почему Java разрешает эти элементы, если я не могу получить к ним доступ извне? Я не могу получить к ним доступ даже внутри Season
перечисления. Я использую Java 11.
Ответ №1:
Это связано с тем, что класс FALL
константы является подклассом Season
класса — вы можете представить его, поскольку вы объявили его как анонимный класс.
Вы можете эмулировать подобную ситуацию и без перечислений:
public static void main(String[] args) {
class C {
public int i;
}
C c = new C() {
public int a;
};
System.out.println(c.a); // wont compile
}
c
Экземпляр по-прежнему обрабатывается как C
класс (несмотря на то, что фактический класс является чем-то вроде C$1
), и a
в классе нет поля C
. Java позволяет a
field обслуживать членов подкласса, а не кого-либо извне. Подкласс существует, но недоступен буквально. Возможен доступ к отражению. То же самое относится и к вашему примеру перечисления.
Комментарии:
1. После этого я должен добавить небольшое примечание: есть разница между моим примером и
Season
примером enum. Это класс, созданный за сценой, тогда как это явно определенный анонимный класс.Season.FALL.getClass()
C$1
Я могу изменить объявлениеC c
наvar c
в моем примере, и код становится компилируемым (см. nipafx.dev/java-var-anonymous-classes-tricks для лучшего объяснения этого трюка). Я не могу придумать, как применить этот трюк для захвата классаFALL
константы перечисления.
Ответ №2:
Для определения также внутренних атрибутов как enum это будет работать:
enum Season {
UNDEFINED,
WINTER(Phenomenon.RAIN),
SPRING(Phenomenon.WIND),
SUMMER(Phenomenon.HOT),
FALL(Phenomenon.RAIN, Phenomenon.WIND);
enum Phenomenon {
RAIN,
WIND,
HOT
};
Phenomenon[] phenomena;
Season(Phenomenon... phenomena) {
this.phenomena = phenomena;
}
@Override
public String toString() {
return this.name() ": " Arrays.toString(phenomena);
}
}
Затем печать / поиск:
for (Season s : Season.values()) {
System.out.println(s);
}
System.out.println();
Season s = Season.SPRING;
for (Phenomenon p : new Phenomenon[] { Phenomenon.HOT, Phenomenon.WIND }) {
if (Arrays.binarySearch(s.phenomena, p) >= 0) {
System.out.println(String.format("Phenomenon [%s] happens in season [%s]", p, s.name()));
} else {
System.out.println(String.format("Phenomenon [%s] does not happen in season [%s]", p, s.name()));
}
}
будет выводить:
UNDEFINED: []
WINTER: [RAIN]
SPRING: [WIND]
SUMMER: [HOT]
FALL: [RAIN, WIND]
Phenomenon [HOT] does not happen in season [SPRING]
Phenomenon [WIND] happens in season [SPRING]
Ответ №3:
Не уверен, почему вы хотите это сделать, но вы можете сделать это так:
public enum Season {
WINTER,
SPRING,
SUMMER,
FALL;
public static final String RAIN = "rain";
public static final String WIND = "wind";
}
Если вы хотите, чтобы эти два поля были доступны только в FALL
, это невозможно. Каждое значение перечисления относится к одному и тому же конечному классу, и если у вас есть статическое поле в классе, оно доступно независимо от того, на какое значение класса вы ссылаетесь.
Ответ №4:
Это потому, что объявление Season не принимает эти методы и свойства.
Попробуйте создать более подробное перечисление, например:
public enum Season {
WINTER,
SPRING,
SUMMER,
FALL("rain", "wind");
private String rain;
private String wind;
private Season () {}
private Season(String rain, String wind) {
this.rain = rain;
this.wind = wind;
}
public String getRain() { return this.rain; }
public String getWind() { return this.wind; }
}
Таким образом, вы можете получить доступ к этим свойствам следующим образом:
System.out.println(Season.FALL.getRain());