열거형 생성자가 정적 필드에 액세스할 수 없는 이유는 무엇입니까?
열거형 생성자가 정적 필드 및 메서드에 액세스할 수 없는 이유는 무엇입니까?이것은 클래스에서는 완전히 유효하지만 열거형에서는 허용되지 않습니다.
제가 하려는 것은 정적 지도에 열거형 인스턴스를 저장하는 것입니다.생략형으로 검색할 수 있는 코드 예를 다음에 나타냅니다.
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);
}
}
열거형이 생성자에서 정적 참조를 허용하지 않으므로 이 작업은 작동하지 않습니다.다만, 클래스로 실장했을 경우는, 다음의 검색만 가능합니다.
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
}
스태틱 필드(Enum 값을 나타내는 필드 포함)는 텍스트 순서로 초기화되며 열거 값은 항상 다른 필드보다 우선하기 때문에 모든 스태틱필드가 초기화되기 전에 생성자가 호출됩니다.클래스 예에서는 SUNDAY 이후인 경우 클래스 초기화 시 예외가 발생합니다.
네, 조금 귀찮은 일이지만 좀 더 나은 설계가 가능했을지도 모릅니다.
하지만, 제 경험상 일반적인 대답은,static {}
모든 스태틱 이니셜라이저의 마지막에 블록하고 모든 스태틱초기화를 수행합니다.EnumSet.allOf
모든 가치를 얻을 수 있습니다.
JLS에서 인용한 "Enum Body Declarations" 섹션:
이 규칙이 없으면 실행 시 enum 유형에 고유한 초기화 순환으로 인해 합리적인 코드가 실패할 수 있습니다.('self-type' 스태틱필드를 가진 클래스에는 순환이 존재합니다).다음은 실패할 수 있는 코드 종류의 예입니다.
enum Color { RED, GREEN, BLUE; static final Map<String,Color> colorMap = new HashMap<String,Color>(); Color() { colorMap.put(toString(), this); } }
이 열거 유형을 정적 초기화하면 NullPointer가 느려집니다.열거 상수에 대한 생성자가 실행될 때 정적 변수 colorMap이 초기화되지 않기 때문에 예외가 발생합니다.위의 제한으로 인해 이러한 코드가 컴파일되지 않습니다.
이 예는 올바르게 동작하도록 쉽게 리팩터링할 수 있습니다.
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);
}
클래스가 JVM에 로드되면 정적 필드는 코드에 표시되는 순서대로 초기화됩니다.예를 들어,
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();
}
}
출력은 0이 됩니다.test4 초기화는 스태틱 초기화 프로세스에서 이루어지며, 이 시간 동안 j는 나중에 나타나듯이 아직 초기화되지 않았습니다.이제 j가 test4 앞에 오도록 정적 이니셜라이저의 순서를 바꿉니다.출력은 6이 됩니다.그러나 Enums의 경우 정적 필드의 순서를 변경할 수 없습니다.열거형의 첫 번째 항목은 실제로 열거형의 정적 최종 인스턴스인 상수여야 합니다.따라서 enum의 경우 열거 상수보다 먼저 정적 필드가 초기화되지 않음을 항상 보장합니다.열거형 생성자에서 사용하기 위해 정적 필드에 적절한 값을 지정할 수 없으므로 열거형 생성자에서 액세스하는 것은 의미가 없습니다.
언급URL : https://stackoverflow.com/questions/443980/why-cant-enums-constructor-access-static-fields
'itsource' 카테고리의 다른 글
정수에서 BigInteger로 변환 (0) | 2022.09.19 |
---|---|
MariaDB Centos 6.5 mysql.libs 충돌 (0) | 2022.09.19 |
잘못된 DUBLE 값: DATATYPE 10진수(10,2)의 SUM()에서 " "이(가) 잘렸습니다. (0) | 2022.09.19 |
안드로이드에서 비행기 모드를 감지하려면 어떻게 해야 하나요? (0) | 2022.09.19 |
MariaDB 5.3에서 5.5로의 업그레이드 (0) | 2022.09.19 |