[Java] Enumerate에 관한 관찰

8243 단어 JDK5JavaJDK5

JDK 1.5 이전 Enum 생성법

JDK 5 이전에는 열거형을 쓰려면 여러 Enumerate 생성 패턴에 따라 만들어서 썼다. 가장 일반적인 방법은 public static final int로 필드를 선언하는 것이었다.

1. 기본적인 static final int 선언 방법

class Month{
    public static final int JAN = 1;
    ...
}

그러나 이 방법은 Type-Safe 하지 않은 방법이기에 오류가 발생하기 쉬웠다.
심지어 위의 예시의 경우는 숫자로 되어있기에, 1~12의 값이 아닌 13, 심지어 음수까지도 사용할 수 있다. 만약 다른 클래스에서도 동일한 방식으로 선언하는 경우, 서로 다른 클래스간의 비교 연산 또한 아무 문제 없이 가능했다.
이러한 경우를 시스템적으로 제약할 수 없으므로, 버그가 언제든지 생길수 있는 구조다.
출력했을 때도 단순한 숫자값이 찍히므로 유의미한 정보를 얻기가 어려웠다.

그래서 int로 선언하지 않고 아래와 같이 선언하는 방법이 있다.

2. Type-safe한 선언 방법

class Month{
    public static final Month JAN = new Month();
    ...
    protected Month(){} 
}

위의 코드의 경우는 Type-Safe하지만 Jan의 다음달을 구하는 등의 연산을 처리하기는 어려운 구조이다. 무엇보다 전체 요소를 가져오거나 비교연산을 하는데는 부적합한 구조이다.

3. List가 포함된 선언방법

class Month{
    public static final List MONTHS;
    
    public static final Month JAN;
    ...
    
    private static final Month[] MONTH_ARRAY;
    
    protected Month(){} 
    
    static {
    	JAN = new Month();
        ...
        MONTH_ARRAY = { JAN, ...};
        MONTHS = Collections.unmodifiableList(Arrays.asList(MONTH_ARRAY));
    }
}

위의 코드는 내부에 static으로 List의 구현체를 두는 방식으로 위에서 말한 문제점들을 해결했지만, 단순한 기능을 구현하기 위해서 너무 긴 코드를 작성해야 하는 문제가 있었다.

그러나 JDK 5에 들어서 enum을 언어적으로 지원하므로 위처럼 번거로운 작업을 할 필요가 없어졌다.

After JDK 1.5

기본적인 enum 선언방법

enum Month{
    JAN, 
    ....
}

이제는 Type-safe하며, 출력을 찍었을때 정보를 얻을 수 있고, 번거로운 코드 작업을 할 필요가 없다.

모든 enum 타입은 java.util.Enum을 상속받게끔 되어있고, Enum은 Comparable와 Serializable을 상속받는다. 이로 인해서 abstract class인 Enum에 선언된 name, ordinal등의 메서드를 사용할 수 있다. 또한, 컴파일러에 의해 values, valueOf 메서드가 생성되기 때문에 별다른 코드 작성 없이도 해당하는 기능들을 사용 할 수 있다.

바이트 코드를 기반으로 다시 코드를 작성해보면 아래와 같은 형태를 띄고 있는 것을 알 수 있다.

바이트 코드에서 복원한 Enum

    enum Month extends java.util.Enum<Month>{
        public final static Month JAN;
        public final static Month FEB;
        ...
        private final static Month[] VALUES;

        public static Month[] values(){
            return VALUES.clone();
        }

        public static Month valueOf(String name){
            Class clazz = Month.getClass();
            return (Month)Enum.valueOf(clazz,name);
        }

        private Month(String name, int ordinal){
            super(name,ordinal);
        }

        static{
            JAN = new Month("JAN",0);
            FEB = new Month("FEB",1); 
            ...
            VALUES[0] = JAN;
            VALUES[1] = FEB;
            ...
        }
    }

코드를 복원 해보니 3. List가 포함된 선언방법과 구조가 크게 다르지 않다. 그러나 enum으로 선언하면 저런 번거로운 작업을 컴파일러가 대신 해주는데다가, Comparable, Serializable의 기능까지 사용할 수 있으므로, enum을 사용하는것이 권장된다.

좋은 웹페이지 즐겨찾기