자바의 정석에서도 Enum에 대한 부분이 분명히 있었지만,
자바의 정석에서는 Enum에 대해 그렇게 와닫지 않았다. (이해 못했단 뜻 ㅎ)
아마 Enum의 사용법을 대강이라도 본 적이 없었다면 아마 손 대지도 못했을 것 같다.
그래서 Enum에 대해 제대로 알아보자
Enum이란 관련 있는 상수의 집합이며, 열거형이라고도 한다.
자바에서는 final로 기본 자료형의 값을 고정할 수 있으며, 이를 상수(Constant) 라고 한다.
어떤 class가 상수의 집합으로 이루어져 있다면, Enum으로 선언 하는 것이 명시적으로 좋다.
Enum을 사용하지 않은 상수의 선언은 아래와 같다.
public class Day {
private final static int MONDAY = 1;
private final static int TUSEDAY = 2;
private final static int WEDNESAY = 3;
private final static int THURDAY = 4;
private final static int FRIDAY = 5;
private final static int SATURDAY = 6;
private final static int SUNDAY = 7;
public static void main(String[] args) {
int day= MONDAY;
switch (day) {
case MONDAY : ...
case TUSEDAY : ...
...
}
}
}
위와 같이 final과 static을 사용하여 한 번만 할당되고 바꿀수 없게 해줄 수 있다.
하지만 요일 뿐만 아니라 다른 상수의 선언이 필요해진다면 상수가 너무 많아지고 상수에 대한 정보를 직관적으로 알 수 없다.
또 만약 중복된 이름으로 정의된 상수는 컴파일러가 오류로 판단한다.
그래서 class 또는 인터페이스를 사용하여 각각의 집합끼리 상수를 정의할 수 있다.
interface DAY {
int MONDAY = 1;
int TUESDAY = 2;
int WEDNESDAY = 3;
int THURDAY = 4;
int FRIDAY = 5;
int SATURDAY = 6;
int SUNDAY = 7;
}
interface MONTH {
int JANUARY = 1;
int FEBRUARY = 2;
int MARCH = 3;
int APRIL = 4;
int MAY = 5;
int JUNE = 6;
int JULY = 7;
int AUGUST = 8;
int SEPTEMBER = 9;
int OCTOBER = 10;
int NOVEMBER = 11;
int DECEMBER = 12;
}
public class Example {
public static void main(String[] args) {
if(DAY.MONDAY == MONTH.JUNUARY) {
System.out.println("두 상수는 같습니다.");
}
}
}
위와 괕이 두 개의 상수 집합을 만들 수 있다.
Interface를 사용해서 public static final 같은 속성을 생략하여 코드의 가독성을 높일 수 도 있다.
하지만 이렇게 DAY.MONDAY == MONTH.JUNUARY 같이 다른 집합의 상수를 비교하는 것은 런타임 단계에서 예기치 못한 문제를 발생시킬 수 있다.
그래서 Interface를 class로 바꾼다면,
각각의 상수들은 데이터 타입은 같지만 서로 다른 데이터 값을 가지게 된다.
이렇게 되면 DAY.MONDAY == MONTH.JUNUARY 같은 비교는 다른 데이터 타입이기 때문에 불가능 하고,
switch문에서 사용되는 데이터 타입은 제한적이기 때문에 switch문의 사용이 힘들다.
이런 문제점을 해결하기 위해 Enum을 사용한다.
enum Day {
MONDAY, TUESDAY, WEDNSEDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY;
}
enum Month {
JANUARY, FEBRUARY, MARCH, APRIL, MAY, JUNE, JULY, AUGUST, SEPTEMBER, OTCOBER, NOVEMBER, DECEMBER;
}
public class Example {
public static void main(String[] args) {
Day day = Day.MONDAY;
switch (day) {
case MONDAY: ...
case TUESDAY: ...
}
}
}
Enum을 사용하면 위와 같이 상수의 이름을 나열하기만 하면 상수가 정의 된다.
또한, switch 문의 레이블은 조건으로 넘어온 데이터 타입을 알고 있다.
그래서 각각의 레이블에서 Enum의 데이터 타입을 생략할 수 있다.
Enum을 사용 하면 아래의 장점이 있다.
Enum의 각 상수에 추가 속성을 부여할 수 있다.
위의 예제와 같이 각각의 요일에 1~7의 값을 부여한다면, 아래와 같다
enum Day {
MONDAY(1), TUESDAY(2), WEDNSEDAY(3), THURSDAY(4), FRIDAY(5), SATURDAY(6), SUNDAY(7);
int value;
private Day(int value) {
this.value = value
}
public int getValue() {
return value;
}
}
생성자의 파라미터를 통해 추가 속성을 Enum 클래스의 필드에 설정해주고,
Getter를 통해 해당 속성을 필요할 때 가져다 쓸 수 있게 한다.
이렇게 메서드나 필드를 Enum 타입에 추가하면 Enum 상수에 어떤 데이터를 연관시킬 수 있다.
Enum의 생성자가 private 인 이유는,
Enum 타입은 고정된 상수들의 집합으로, 런타임 시점이 아닌 컴파일 시점에 모든 값을 알고 있어야한다.
즉 다른 패키지나 클래스에서 Enum 타입에 접근해서 동적으로 어떤 값을 정해줄 수 없다.
따라서 컴파일 시에 타입안정성이 보장된다.
이를 위해 생성자의 접근제어자를 private로 설정해야하고,
이를 통해 Enum타입을 실질적으로 final처럼 만들어 준다.