언어/JAVA

자바 - 열거형(enums)

now0204 2023. 3. 26. 16:51

1. 열거형이란?

- 열거형은 서로 관련된 상수를 묶어놓은 것이다. java의 열거형은 타입도 관리하여 타입에 안전한 열거형이다.

- 마치 인스턴스가 미리 정의된 클래스로 생각해 볼 수 있다.

 

1.2 열거형의 정의와 사용 

 

- enum 열거체명 {상수명1,상수명2..} 등으로 정의할 수 있다.

- 선언 위치는 클래스와 동일하다. 클래스 내부, 외부, 혹은 하나의 클래스파일에 정의할 수 있다.

- 사용법은 열거체 참조변수에 열거체.상수명 혹은 열거형체.valueOf(상수명)

- 모든 열거형의 조상 Enum에 Enum에 기본적으로 사용가능한 메서드들이 정의되어 있다. 

 

enum Direction {EAST,SOUTH,WEST,NORTH}

 Direction dir = Direction.EAST;
 Direction dir2 = Direction.valueOf("SOUTH");

출처: https://nathanh.tistory.com/118

1.3 열거형에 멤버 추가하기 

 

- 열거형 멤버에 여러 값을 할당 할 수 있다. 

- 이때 열거형 멤버들은 미리 선언된 인스턴스와 같고, 열거형 내부에서 인스턴스를 생성하기 위한 생성자 및 메서드를 정의 해야한다. (내부적으로 사용되는 생성자와 변수는 private)

 

enum Direction {
    EAST(1,">"),SOUTH(2,"v"),WEST(3,"<"),NORTH(4,"^");
    private final int value;
    private final String symbol;
    
   private Direction(int value,String symbol){
        this.value= value;
        this.symbol = symbol;
    }
    
    public int getValue() {return this.value;}

}

1.4 추상 메서드 추가하기 

 

- 열거형에 추상메서드를 추가해서 열거형 멤버들이 이를 오버라이딩하게 할 수 있다.

- 이는 마치 추상클래스를 상속받은 클래스가 오버라이딩하는 것과 같다. 

- 각 열거체의 상수별로 오버라이딩을 통해 메서드 내용을 다르게 설정할 수 있다.

 enum Direction {
        EAST(1,">"){
            @Override
            int fare() {
                return EAST.getValue()*2;
            }
        },SOUTH(2,"v") {
            @Override
            int fare() {
                return SOUTH.getValue()+Basic_fare;
            }
        },WEST(3,"<") {
            @Override
            int fare() {
                return WEST.getValue()+Basic_fare;
            }
        },NORTH(4,"^") {
            @Override
            int fare() {
                return NORTH.getValue()+Basic_fare;
            }
        };
        private final int value;
        private final String symbol;

       protected final int Basic_fare=2; //protected로 해야 각 열거형 멤버들이 모두 접근 가능
       private Direction(int value,String symbol){
            this.value= value;
            this.symbol = symbol;
        }
        abstract int fare();
        public int getValue() {return this.value;}
    }

 

2. 열거형의 이해

 

열거형에 대한 더 싶은 이해를 위해 내부 구현에 대해 간단하게 살펴보자

 

enum Direction {EAST,SOUTH,WEST,NORTH}는 아래 코드와 같다. 

 

class Direction{
    static final Direction EAST = new Direction("EAST");
    static final Direction SOUTH = new Direction("SOUTH");
    static final Direction WEST = new Direction("WEST");
    static final Direction NORTH = new Direction("NORTH");
    
    private String name;
    private Direction(String name) {
        this.name=name;
    }
}

- static 상수 열거형 객체 EAST,SOUTH,WEST,NORTH는 객체의 주소를 담고 있고, 이 값은 바뀌지 않으므로 ==로 비교 가능

- 또한 static 상수이므로 열거형이름.EAST등으로 사용가능한 것이다.

 

abstract class MyEnum<T extends MyEnum<T>> implements Comparable<T>{
    static int id=0;
    int ordinal;
    String name ="";
    
    public int ordinal(){return ordinal;}
    MyEnum(String name){
        this.name = name;
        ordinal = id++;
    }
    public int compareTo(T t){
        return ordinal - t.ordinal();
    }
    
    
}
abstract class MyTransportation extends MyEnum{
    static final MyTransportation BUS = new MyTransportation("BUS",100) {
        int fare(int distance) {return distance * BASIC_FARE;
        }
    };
    static final MyTransportation TRAIN = new MyTransportation("TRAIN",100) {
        int fare(int distance) {return distance * BASIC_FARE;
        }
    };
    static final MyTransportation SHIP = new MyTransportation("SHIP",100) {
        int fare(int distance) {return distance * BASIC_FARE;
        }
    };
    static final MyTransportation AIRPLANE = new MyTransportation("AIRPLANE",100) {
        int fare(int distance) {return distance * BASIC_FARE;
        }
    };
    
    abstract int fare(int distance);
    protected final int BASIC_FARE;
    private MyTransportation(String name, int basicfare) {
        super(name);
        BASIC_FARE = basicfare;
    }
    public String name(){return name;}
    
}

 - 객체가 생성될 때마다 ordinal에 저장

- <T enxtends MyEnum<T>> 타입 T가 MyEnum<T>의 자손이어야 한다는 의미 (compareTo에서 t.ordinal()때문에 이렇게함) 

- 추상메서드를 추가하면, 클래스 앞에 abstract 각 static 멤버들 익명클래스 형태로 추상메서드 구현

 

**여기서 MyEnum<T> <- 이 <T>는 큰 의미는 없다.

T extedns MyEnum인 것과 마찬가지 -> 제네릭 클래스에서 타입변수의 다형성 x (원시타입은 다형성 인정, 타입변수는 안됨)

따라서 MyEnum<String,Integer...등등 뭐던 간에> T는 MyEnum<> 혹은 그 자손만 담을 수 있다.

 

 

참고자료- 자바의 정석 남궁성 저