Java에서의 enum 타입

enum Type{ // abstract class
	ADD, // public static final class ADD extends Type{}
	SUB; // public static final class SUB extends Type{}
}

기본적으로 enum은 추상클래스이고, 그 하위에 선언된 각 열거형 변수는 실제로는 변수가 아니라 enum 의 타입을 상속받은 하위 클래스이다. 이 하위 클래스는 외부에 노출되어 있고 생성할 필요가 없으며 런타임에 교체가 불가능하므로 public static final 타입을 갖는다.

 

enum은 기본적으로 추상 클래스이나, 다른 클래스로부터 상속을 받지 못한다.

하지만 interface는 상속을 받을 수 있다. Enum에 함수가 들어갈 수 있는지 완전 몰랐다,,,,

interface Interface{
    public void api();
}


enum Type implements Interface{
    ADD{
        public void api(){ System.out.println("ADD api"); }
    },
    SUB{
        public void api(){ System.out.println("SUB api"); }
    };
}

이 특성을 이용해서 디자인 패턴에 나오는 수많은 패턴들을 enum을 통해 구현할 수 있다.

enum이 public static final 이라는 점은 Singleton과 유사한 특성을 지니고 있다.

따라서 중복 생성이 안되면서도 일반 클래스 기능을 할 수도 있고, 필요한 때에는 enum의 특성을 활용할 수도 있다.

이 강력한 특성 때문에

Singleton 패턴, Abstract Factory 패턴, Factory Method 패턴, State 패턴, Strategy 패턴, Visitor 등 다양한 패턴의 enum 버전이 있다.

 

이 외에도 enum은 추상 클래스이므로 함수를 선언할 수 있고, 추상 메소드 또는 static 메소드의  선언도 가능하다.

enum Type{
    ADD,
    SUB;
    public void api(){ System.out.println("api()"); }
}
enum Type{
    ADD{
        public void api(){ System.out.println("ADD api"); }
    },
    SUB{
        public void api(){ System.out.println("SUB api"); }
    };
    abstract public void api();
    public static int size(){ return Type.size(); }
}

 

또한 클래스이므로 생성자도 선언할 수 있어야 한다.

enum Type{
    ADD(0),// 생성자에게 필요한 인자는 () 안에 넣는다.
    SUB(1); //
    int value;
    private Type(int value){ this.value = value; }   // 이것이 생성자.
    public int value(){ return value; }
}

enum 클래스를 인덱스로 활용할 수 있도록 value 라는 int 형 값을 생성시에 인자로 받도록 했다. Java의 enum은 클래스이기 때문에 C언어에서 처럼 값으로 활용할 수가 없다. 대신에 이처럼 생성자를 통해 인자로 받은 값을 가지고 있다가 값이 필요한 경우 value() 함수를 호출함으로써 값으로도 사용이 가능하다.

이때 생성자가 private인 것에 주목해야 한다.

enum은 외부에서 생성이 불가능하기 때문에 생성자는 항상 private으로 선언해 주어야 한다.

 

enum은 클래스이므로 하위 타입들도 모두 toString() 함수를 가지고 있다. 그 결과 값은 기본적으로 자신의 선언된 이름과 같다. ADD.toString()은 "ADD" 값이 결과값이다. 이러한 특성은 매우 유용한데, 특히 데이터베이스에 저장할 때 그렇다.

DB의 가독성 측면에서 문자열을 활용한 경우에 문자열을 입력받아 타입을 리턴하도록 하면

코드 상에서 문자열 대신 enum을 활용할 수 있으므로 코딩이 편리해진다.

public static Type getTypeByString(String str){
    for(Type each : values()){
        if(each.toString().equals(str)){
            return each;
        }
    }
    return null;
}

 

enum 타입이 제공하는 기본 함수로 enum의 순서를 알 수 있는 함수가 있다.

public int ordinal();

위 ordinal() 이라는 함수인데 이 함수는 선언된 enum의 하위 타입이 몇 번째 순서로 선언되었는지를 알 수 있다.(순서의 시작 값은 0이다.) 가령 위에서 선언한 ADD 타입의 경우 0이 리턴되고, SUB의 경우 1이 리턴된다. 이 특성을 이용하면 enum을 인덱스로도 활용이 가능하다.

 

Java에서의 enum은 열거형의 특성과 클래스의 특성을 함께 가지고 있다는 장점이 있다. toString() 함수를 가지고 있다는 것만으로도 디버깅을 얼마나 쉽게 만들어 주는지 모른다. 그 밖에도 데이터 베이스와의 연동, switch-case 문에 대한 활용, 인터페이스 상속을 활용한 디자인 패턴 등 다양한 곳에 활용할 수 있다.

 


그렇다면 enum 타입을 배열의 인덱스로 활용하는 방법을 알아보자

class Distance{
    private int east;
    private int west;
    private int north;
    private int south;

    public void setEast(int east){ this.east = east; }
    public void setWest(int west){ this.west = west; }
    public void setNorth(int north){ this.north = north; }
    public void setSouth(int south){ this.south = south; }

    public int getEast() { return east; }
    public int getWest() { return west; }
    public int getNorth() { return north; }
    public int getSouth() { return south; }
}

위와 같은 클래스를 보면

모두 같은 타입(int)의 변수를 선언하고 있고, 모두 getter와 setter를 제공하고 있음을 알 수 있다. 그리고 동서남북을 나타내는 변수들이므로 서로 연관성도 있어 보인다. 이런 경우에는 enum 타입을 하나 선언해서 동서남북을 가리키는 서브 타입을 만들고 이것을 인덱스로 활용하는 방법을 사용하면 중복이 제거된다.

enum Direction{
    EAST,
    WEST,
    NORTH,
    SOUTH;
}

class Distance{
    // 각 방향별로 선언되었던 변수를 하나의 배열로 선언
    private int distance[] = new int[Direction.values().length];
    
    public int get(Direction direction){ 
        return distance[direction.ordinal()]; 
    }
    public void set(Direction direction, int value){ 
        distance[direction.ordinal()] = value; 
    }
}

enum 하위 타입의 개수를 알아내는 방법은 보통 Type.values().length 를 이용한다. .values() 함수는 enum 하위 타입들을 배열화하여 리턴해주는 함수이다. .length는 잘 알다시피 배열의 길이를 나타내는 배열 객체의 변수이다. 그리고 이들은 앞서 말한 바와 같이 컴파일 타임에 결정되기 때문에 배열의 개수 초기화에도 사용할 수 있다.

get함수에서는 enum 타입인 Direction  하위 타입을 어떻게 인덱스 숫자로 바꾸느냐가 중요한데, JAVA에서는 ordinal() 이라는 함수를 통해 숫자로 바꿀 수 있다. int ordinal() 함수는 해당 서브 enum 타입의 정의 순서에 따른 숫자를 리턴한다. 가령 EAST.ordinal() = 0, WEST.ordinal() = 1......와 같은 방식이다. 이것은 배열의 인덱스 값과 같은 값이다. 따라서 전혀 문제 없이 사용할 수 있다.

 

 

 

https://effectiveprogramming.tistory.com/entry/enum%EC%9D%98-%ED%99%9C%EC%9A%A9%EB%B2%95?category=660010

 

enum의 활용법

C언어에서 enum은 단순히 상수형 변수 역할에 지나지 않았다. 하지만 Java에서는 매우 다른 특성들을 지니고 있다. 이 특성들 중에는 특별한 것들도 있어서 기존과는 다른 여러 방식으로 enum을 활�

effectiveprogramming.tistory.com

 

+ Recent posts