enum의 생성자가 정적 필드에 액세스 할 수없는 이유는 무엇입니까?
열거 형의 생성자가 정적 필드 및 메서드에 액세스 할 수없는 이유는 무엇입니까? 이것은 클래스에서 완벽하게 유효하지만 열거 형에서는 허용되지 않습니다.
내가하려는 것은 정적 맵에 열거 형 인스턴스를 저장하는 것입니다. 약어로 조회 할 수있는 다음 예제 코드를 고려하십시오.
public enum Day {
Sunday("Sun"), Monday("Mon"), Tuesday("Tue"), Wednesday("Wed"), Thursday("Thu"), Friday("Fri"), Saturday("Sat");
private final String abbreviation;
private static final Map<String, Day> ABBREV_MAP = new HashMap<String, Day>();
private Day(String abbreviation) {
this.abbreviation = abbreviation;
ABBREV_MAP.put(abbreviation, this); // Not valid
}
public String getAbbreviation() {
return abbreviation;
}
public static Day getByAbbreviation(String abbreviation) {
return ABBREV_MAP.get(abbreviation);
}
}
enum은 생성자에서 정적 참조를 허용하지 않으므로 작동하지 않습니다. 그러나 클래스로 구현되면 찾을 수 있습니다.
public static final Day SUNDAY = new Day("Sunday", "Sun");
private Day(String name, String abbreviation) {
this.name = name;
this.abbreviation = abbreviation;
ABBREV_MAP.put(abbreviation, this); // Valid
}
생성자는 정적 필드가 모두 초기화되기 전에 호출됩니다. 정적 필드 (열거 형 값을 나타내는 필드 포함)는 텍스트 순서로 초기화되고 열거 형 값은 항상 다른 필드 앞에 오기 때문입니다. 클래스 예제에서는 ABBREV_MAP가 초기화 된 위치를 표시하지 않았습니다. SUNDAY 이후 이면 클래스가 초기화 될 때 예외가 발생합니다.
예, 약간의 고통이며 아마도 더 잘 설계되었을 수 있습니다.
그러나 내 경험상 일반적인 대답 static {}
은 모든 정적 이니셜 라이저 끝에 블록을두고 EnumSet.allOf
모든 값을 가져 오는 데 사용하여 모든 정적 초기화를 수행 하는 것입니다.
JLS의 "Enum Body Declarations"섹션 에서 인용 :
이 규칙이 없으면 enum 유형에 내재 된 초기화 순환 성으로 인해 런타임에 합리적인 코드가 실패 할 것입니다. ( "자체 유형"정적 필드가있는 모든 클래스에는 순환 성이 존재합니다.) 다음은 실패 할 수있는 코드 유형의 예입니다.
enum Color { RED, GREEN, BLUE; static final Map<String,Color> colorMap = new HashMap<String,Color>(); Color() { colorMap.put(toString(), this); } }
이 열거 형 유형의 정적 초기화 는 열거 형 상수에 대한 생성자가 실행될 때 정적 변수 colorMap이 초기화되지 않기 때문에 NullPointerException을 throw 합니다. 위의 제한은 이러한 코드가 컴파일되지 않도록합니다.
예제는 제대로 작동하도록 쉽게 리팩토링 할 수 있습니다.
enum Color { RED, GREEN, BLUE; static final Map<String,Color> colorMap = new HashMap<String,Color>(); static { for (Color c : Color.values()) colorMap.put(c.toString(), c); } }
리팩토링 된 버전은 정적 초기화가 위에서 아래로 발생하므로 명확하게 정확합니다.
아마도 이것은 당신이 원하는 것입니다
public enum Day {
Sunday("Sun"),
Monday("Mon"),
Tuesday("Tue"),
Wednesday("Wed"),
Thursday("Thu"),
Friday("Fri"),
Saturday("Sat");
private static final Map<String, Day> ELEMENTS;
static {
Map<String, Day> elements = new HashMap<String, Day>();
for (Day value : values()) {
elements.put(value.element(), value);
}
ELEMENTS = Collections.unmodifiableMap(elements);
}
private final String abbr;
Day(String abbr) {
this.abbr = abbr;
}
public String element() {
return this.abbr;
}
public static Day elementOf(String abbr) {
return ELEMENTS.get(abbr);
}
}
중첩 된 클래스를 통해 문제가 해결되었습니다. 장점 : CPU 사용량이 더 짧고 더 좋습니다. 단점 : JVM 메모리에 클래스가 하나 더 있습니다.
enum Day {
private static final class Helper {
static Map<String,Day> ABBR_TO_ENUM = new HashMap<>();
}
Day(String abbr) {
this.abbr = abbr;
Helper.ABBR_TO_ENUM.put(abbr, this);
}
public static Day getByAbbreviation(String abbr) {
return Helper.ABBR_TO_ENUM.get(abbr);
}
When a class is loaded in the JVM then static fields are initialized in the order in which they appear in code. For e.g.
public class Test4 {
private static final Test4 test4 = new Test4();
private static int j = 6;
Test4() {
System.out.println(j);
}
private static void test() {
}
public static void main(String[] args) {
Test4.test();
}
}
The output will be 0. Note that test4 initialization takes place in static initialization process and during this time j is not yet initialized as it appears later. Now if we switch order of static initializers such that j comes before test4. The output will be 6.But in case of Enums we cannot alter order of static fields. The first thing in enum must be the constants which are actually static final instances of enum type.Thus for enums its always guaranteed that static fields wont be initialized before enum constants.Since we cannot give any sensible values to static fields for use in enum constructor, it would be meaningless to access them in enum constructor.
참고URL : https://stackoverflow.com/questions/443980/why-cant-enums-constructor-access-static-fields
'Programming' 카테고리의 다른 글
달력이 잘못된 달을 반환 함 (0) | 2020.08.24 |
---|---|
특정 문자를 제외하고 공백이 아닌 문자를 일치시키는 방법은 무엇입니까? (0) | 2020.08.23 |
Math.Floor (Double)가 Double 유형의 값을 반환하는 이유는 무엇입니까? (0) | 2020.08.23 |
PHP 및 mySQL : 2038 년 버그 : 무엇입니까? (0) | 2020.08.23 |
프로그래밍 방식으로 기기의 Android API 수준을 얻습니까? (0) | 2020.08.23 |