enum

Posted by yunki kim on February 21, 2022

  자바 5 이전에는 enum이 존재하지 않았기 때문에 interface를 사용해 이를 대체했다. 하지만 이 방식은 다음과 같이 잘못된 연산을 할 수 있는 문제를 가지고 있었다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
interface Animal {
    int DOG = 1;
    int CAT = 2;
}
 
interface Person {
    int MAN = 1;
    int WOMAN = 2;
}
 
public class Main {
    public static void main(String[] args) {
        who(Person.MAN); // 남성
        who(Animal.DOG); // 남성(잘못된 출력)
    }
 
    public static void who(int man) {
        switch (man) {
            case Person.MAN -> System.out.println("남성");
            case Person.WOMAN -> System.out.println("여성");
        }
    }
}
cs

  하지만 enum이 도입된 이후 enum을 사용하면 위와 같은 문제가 발생하지 않는다. Animal 열거체 값은 DOG, CAT이고 Person의 값은 MAN, WOMAN이기 때문이다.

1
2
3
4
5
6
7
enum Animal {
    DOG, CAT
}
 
enum Person {
    MAN, WOMAN
}
cs

  열거체 안에 위치한 이름들을 열거체 값(Enumerated Values)라 한다.

  열거체은 클래스와 유사한 성격을 띄고 있기 때문에 참조 변수에 선언할 수 있다. 하지만 참조변수는 해당 열거체 내에서 선언된 열거체 값만 대입할 수 있다.

1
2
3
4
5
enum Animal {
    DOG, CAT
}
 
Animal animal = Animal.DOG; // Animal에 선언된 DOG 열거체 값 대입
cs

열거체 값의 정체

  아래의 예시는 열거체 값이 해당 클래스의 인스턴스라는 것을 증명한다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
enum Person {
    MAN, WOMAN;
 
    private Person() {
        System.out.println("default constructor called");
    }
 
    @Override
    public String toString() {
        return "person";
    }
}
 
public class Main {
    public static void main(String[] args) {
        System.out.println(Person.MAN);
        // 출력:
        // default constructor called
        // default constructor called
        // person
    }
 
}
cs

  모든 열겨형은 java.lang.Enum<E> 클래스를 상속하고 Enum<E>는 Object 클래스를 상속한다. 따라서 열겨형을 클래스로 볼 수 있다. 그리고 두 열거체 값은 Person 인스턴스를 참조하는 참조 변수다(toString 메서드 호출이 이를 증명한다).

  위 예제에서 열거체 값이 두 개 이기 때문에 생성자가 두 번 호출되었다. 설명을 위해 임의적으로 private 생성자를 추가했지만 열거체은 생성자가 없으면 private 디폴트 생성자가 삽입된다. 따라서 직접 인스턴스를 생성하는 것은 불가능 하다.

 

열거체 값의 선언

  열거체 값의 선언은 다음과 같이 ()안에 할 수 있다. 이때 해당 값을 정의하기 위해서는 해당 값을 저장할 상태 하나와 생성자가 필요하다. 이때의 생성자는 private이 아닌 default이다. 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
enum Person {
    MAN(29), WOMAN(30); // 열거형 값의 선언
 
    private final int age;
 
    Person(int age) {
        this.age = age;
    }
 
    public int getAge() {
        return age;
    }
 
    @Override
    public String toString() {
        return age + "";
    }
}
 
public class Main {
    public static void main(String[] args) {
        System.out.println(Person.WOMAN); // toString 에서 반환: 30
        System.out.println(Person.MAN.getAge()); // getAge 에서 반환: 29
    }
 
}
cs

Enum 클래스의 메소드

  Enum 클래스에는 여러 메소드들이 정의되 있고 대표적인 메소드들과 사용법은 다음과 같다.

메소드 설명
static E values() 해당 열거체의 모든 상수를 저장한 배열을 생성해 반환
static E valueOf(String name) 전달된 문자열과 일치하는 해당 열거체의 상수를 반환
String name() 해당 열거체 상수의 이름을 반환
int ordinal() 해당 열거체 상수가 열거체 정의에서 정의된 순서를 반환
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
enum Person {
    MAN(29), WOMAN(30);
 
    private final int age;
 
    Person(int age) {
        this.age = age;
    }
 
    public int getAge() {
        return age;
    }
 
    @Override
    public String toString() {
        return age + "";
    }
}
 
public class Main {
    public static void main(String[] args) {
        System.out.println(Person.valueOf("MAN")); // 29
        System.out.println(Arrays.toString(Person.values())); // [29, 30]
        System.out.println(Person.MAN.name()); // MAN
        System.out.println(Person.MAN.ordinal()); // 0
    }
 
}
cs