itsource

열거형 생성자가 정적 필드에 액세스할 수 없는 이유는 무엇입니까?

mycopycode 2022. 9. 19. 23:41
반응형

열거형 생성자가 정적 필드에 액세스할 수 없는 이유는 무엇입니까?

열거형 생성자가 정적 필드 및 메서드에 액세스할 수 없는 이유는 무엇입니까?이것은 클래스에서는 완전히 유효하지만 열거형에서는 허용되지 않습니다.

제가 하려는 것은 정적 지도에 열거형 인스턴스를 저장하는 것입니다.생략형으로 검색할 수 있는 코드 예를 다음에 나타냅니다.

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

반응형