# Enum 이란? - 열거형이라고도 하며, 특정 값들의 집합을 의미한다. - 자바에서 특정 값(상수) 들의 집합을 표현하는데 사용된다. - 예를 들어 계절을 표현할 때, `봄`, `여름`, `가을`, `겨울`을 표현할 때 사용할 수 있다. ## 과거엔 상수를 어떻게 정의했는가? - 자바에서는 상수를 정의하는 몇가지 방법이 있다 - `static final` 키워드를 사용하여 정의 - `interface`를 사용하여 정의 - 자체 클래스를 사용하여 정의 - `enum`을 사용하여 정의 - `enum`은 자바 5부터 지원하는 기능이다. (이전 버전에서는 사용할 수 없다.) ### static final 키워드를 사용하여 정의 - `static final` 은 `상수`를 표현하기에 적합하기에 예전부터 많이 사용되었다. ```java public class Season { public static final int SPRING = 0; public static final int SUMMER = 1; public static final int FALL = 2; public static final int WINTER = 3; public static void main(String[] args) { int season = Season.SPRING; switch (season) { case Season.SPRING: System.out.println("봄"); break; case Season.SUMMER: System.out.println("여름"); break; case Season.FALL: System.out.println("가을"); break; case Season.WINTER: System.out.println("겨울"); break; } } } ``` 하지만 이 방법은 접근제어자들 때문에 가독성이 그렇게 좋지 못하다라는 단점이 존재하며, 그룹화가 되어있지 않다는 단점이 존재한다. ### interface를 사용하여 정의 - 인터페이스의 모든 멤버는 `public static final`이기 때문에 상수를 정의하기에 적합하다. ```java public interface Season { int SPRING = 0; int SUMMER = 1; int FALL = 2; int WINTER = 3; } public class Main { public static void main(String[] args) { int season = Season.SPRING; switch (season) { case Season.SPRING: System.out.println("봄"); break; case Season.SUMMER: System.out.println("여름"); break; case Season.FALL: System.out.println("가을"); break; case Season.WINTER: System.out.println("겨울"); break; } } } ``` 이 방법으로 정의 시 결국 상수가 `정수`로 정의되는 문제가 발생한다. 상수는 `변하지 않는 값`이기도 하지만 `고유한 값`이라는 이름도 내포되어 있다. 따라서 정수와 비교가 가능해지고, 정수와 비교 시 `참`이 나올 수도 있는 문제가 발생한다. 예를 들어 `Season.SPRING`과 `0`을 비교하면 `true`가 나올 수도 있다. ### 자체 클래스를 사용하여 정의 - 자체 클래스를 사용하여 정의하는 방법은 `static final` 키워드를 사용하여 정의하는 방법과 비슷하다. - 부가적으로 생성자를 `private`으로 선언하여 외부에서 객체를 생성하지 못하도록 막아준다. - 이 방법은 `static final` 키워드를 사용하여 정의하는 방법과 비슷하지만, `private` 생성자를 선언하여 외부에서 객체를 생성하지 못하도록 막아준다는 점이 다르다. ```java public class Season { public static final Season SPRING = new Season(); public static final Season SUMMER = new Season(); public static final Season FALL = new Season(); public static final Season WINTER = new Season(); private Season() { } } ``` ```java public class Main { public static void main(String[] args) { Season season = Season.SPRING; if (season == Season.SPRING) { System.out.println("봄"); } else if (season == Season.SUMMER) { System.out.println("여름"); } else if (season == Season.FALL) { System.out.println("가을"); } else if (season == Season.WINTER) { System.out.println("겨울"); } } } ``` 이 방법을 사용할 경우 `정수`가 아닌 `객체`로 정의되기 때문에 정수와 비교할 수 없다는 장점이 있지만 가독성이 좋지 않다는 단점과 `switch`를 사용할 수 없다는 단점이 존재한다. `switch` 조건에 들어가는 데이터 타입은 `정수`, `문자열`, `Enum`만 가능하기 때문이다. ## 자바의 Enum - 자바에서는 `Enum`을 사용하여 상수를 정의할 수 있다. - C언어의 `enum`은 단순한 정수형 상수를 정의한다 - 자바의 Enum은 `java.lang.Enum` 클래스를 상속받는 특수한 **특수한 클래스**다 - 클래스이기 때문에 생성자, 필드, 메서드를 가질 수 있다. - Enum은 열거형 상수들을 관리하는 클래스이다. - 열거형 상수들은 Enum 클래스의 `static final` 멤버들이다. - 생성자의 접근 제어자는 `private`이다. - 외부에서 객체를 생성할 수 없다. - Enum 클래스의 생성자는 다음과 같은 특징을 가진다. - `private`이다. - JVM에 의해 호출된다. - Enum 클래스의 멤버들을 초기화하는 역할을 한다. - Enum 클래스의 멤버들은 다음과 같은 특징을 가진다. - `public static final`이다. - 생성자에 의해 초기화된다. - 멤버들은 Enum 클래스의 객체이다. - `==` 연산자를 통해 비교할 수 있다. - 단 한 번만 생성되기는게 보장되기 때문에 참조 비교를 해도 된다. ## Enum의 장점 - 코드가 단순해지며 가독성이 좋아진다 - 키워드가 `enum`이기 때문에 상수임을 알 수 있다 - 허용 가능한 값들을 제한할 수 있다 - Type Safety를 보장한다 - switch 문을 사용할 수 있다 - 여러 IDE의 도움을 받을 수 있다 - 자동완성, 오타 검증, 리팩토링 등 - 본질적으로 Thread Safe 하다 - Serialization이 자동으로 처리된다 ## Enum 정의하기 ```java enum 열거형이름 { 열거형 상수1, 열거형 상수2, 열거형 상수3, ... } ``` ### Enum 정의 예시 ```java public enum Season { SPRING, SUMMER, FALL, WINTER } ``` > 위 예제에서 `Season`은 Enum의 이름이고, `SPRING`, `SUMMER`, `FALL`, `WINTER`는 Season Enum의 멤버들이다. ## Enum의 고급 기능 - Enum은 클래스이기 때문에 생성자, 필드, 메서드를 가질 수 있다. ```java public enum Season { SPRING("봄"), SUMMER("여름"), FALL("가을"), WINTER("겨울"); private final String name; Season(String name) { this.name = name; } public String getName() { return name; } } ``` ## Enum의 메서드 - 모든 클래스가 `Object` 클래스를 자동 상속하는 것 처럼, Enum 클래스도 무조건 `java.lang.Enum` 이라는 클래스의 상속을 받는다. - `java.lang.Enum` 클래스에는 자체 내장 메서드를 가지고 있으며, 이를 사용할 수 있다. | 메서드 이름 | 설명 | | ----------- | ------------------------------------------------------------ | | values() | Enum의 모든 멤버들을 배열로 반환한다 | | valueOf() | Enum의 멤버 이름으로 Enum 멤버를 찾아서 반환한다 | | ordinal() | Enum의 멤버가 정의된 순서를 반환한다 | | compareTo() | Enum의 멤버가 정의된 순서를 기준으로 비교하여 순서가 앞인지 뒤인지를 반환한다 | | name() | Enum의 멤버 이름을 반환한다 | ### values() - Enum의 모든 멤버들을 배열로 반환한다 ```java public enum Season { SPRING, SUMMER, FALL, WINTER } public class Main { public static void main(String[] args) { Season[] seasons = Season.values(); System.out.println(Arrays.toString(season)); } } ``` ### valueOf() - Enum의 멤버 이름으로 Enum 멤버를 찾아서 반환한다 ```java public enum Season { SPRING, SUMMER, FALL, WINTER } public class Main { public static void main(String[] args) { Season season = Season.valueOf("SPRING"); System.out.println(season); } } ``` ### ordinal() - Enum의 멤버가 정의된 순서를 반환한다 ```java public enum Season { SPRING, SUMMER, FALL, WINTER } public class Main { public static void main(String[] args) { Season season = Season.SPRING; System.out.println(season.ordinal()); } } ``` ### compareTo() - Enum의 멤버가 정의된 순서를 기준으로 비교하여 순서가 앞인지 뒤인지를 반환한다 ```java public enum Season { SPRING, SUMMER, FALL, WINTER } public class Main { public static void main(String[] args) { Season season1 = Season.SPRING; Season season2 = Season.SUMMER; System.out.println(season1.compareTo(season2)); } } ``` ### name() - Enum의 멤버 이름을 반환한다 ```java public enum Season { SPRING, SUMMER, FALL, WINTER } public class Main { public static void main(String[] args) { Season season = Season.SPRING; System.out.println(season.name()); } } ```