Enum(열거형) 클래스

Enum Class

자바에서 enum 클래스는 상수 집합을 정의하는 데 사용되는 특별한 유형의 클래스입니다. 이 클래스는 관련된 상수 그룹을 정의하고, 각각의 상수에 대한 메서드와 속성을 추가할 수 있습니다. enum은 주로 고정된 값들을 표현하는데 사용되며, 예를 들어 요일, 월, 계절 등을 나타내는 데 자주 활용됩니다.

https://whwl.tistory.com/254

기존에 사용하던 상수 등록 방식은 아래와 같습니다. 

class EnumExample {
    private final static int MONDAY = 1;
    private final static int TUESDAY = 2;
    private final static int WEDNESDAY = 3;
    private final static int THURSDAY = 4;
    private final static int FRIDAY = 5;
    private final static int SATURDAY = 6;
    private final static int SUNDAY = 7;
}

대충 코드를 봐도 알 수 있듯이 반복이 되는 코드가 존재하게 되므로 쓸데 없이 길게 보이는 코드들이 많아진다는 문제점이 있습니다. 이를 해결 하기 위해 나온 방식이 바로 열거형 클래스입니다. 

 

다음은 열거형 클래스들을 사용한 방식입니다. 

public enum DayOfWeek {
  MONDAY,
  TUESDAY,
  WEDNESDAY,
  THURSDAY,
  FRIDAY,
  SATURDAY,
  SUNDAY;
}

Ordinal 

열거형 클래스를 사용하게 되면 안에 있는 String 값을 사용하는 것이 아니라 Ordinal 즉, 순서에 대한 값을 사용하게 됩니다. 

 

해당 상수 값들은 ordinal() 메서드를 통해 순서(ordinal) 값을 가져올 수 있습니다. ordinal() 메서드는 열거형 상수가 선언된 순서에 따라 0부터 시작하는 정수 값을 반환합니다.

 

예를 들어, 다음과 같이 정의된 DayOfWeek 열거형 클래스가 있다고 가정해보겠습니다

public enum DayOfWeek {
  MONDAY,
  TUESDAY,
  WEDNESDAY,
  THURSDAY,
  FRIDAY,
  SATURDAY,
  SUNDAY
}

위의 예시에서 MONDAY 상수의 ordinal() 값은 0이며, TUESDAY는 1, WEDNESDAY는 2, 순서대로 증가하게 됩니다.

 

따라서, 열거형 상수의 ordinal() 값을 사용하여 순서를 기준으로 작업을 수행할 수 있습니다. 이 값은 주로 스위치 문 대신 사용되는 경우가 많습니다.

 

다음은 DayOfWeek 열거형 클래스를 사용하여 ordinal() 값을 출력하는 예시 코드입니다.

public class Main {
  public static void main(String[] args) {
    for (DayOfWeek day : DayOfWeek.values()) {
      System.out.println(day + " - Ordinal: " + day.ordinal());
    }
  }
}

위의 예시에서 DayOfWeek.values() 메서드는 DayOfWeek 열거형 클래스의 모든 상수를 배열로 반환하며, 반복문을 통해 각 상수의 이름과 ordinal() 값을 출력합니다.

 

실행 결과는 다음과 같습니다

MONDAY - Ordinal: 0
TUESDAY - Ordinal: 1
WEDNESDAY - Ordinal: 2
THURSDAY - Ordinal: 3
FRIDAY - Ordinal: 4
SATURDAY - Ordinal: 5
SUNDAY - Ordinal: 6

하지만 이러한 ordinal 값을 사용하는 방식에는 매우 치명적인 단점이 존재합니다. 그것은 바로 값이 새롭게 추가 되는 경우에 순번이 밀리게 되면서 기존에 존재하는 값들을 다 변경 해야한다는 큰 문제를 야기합니다. 그렇기 때문에 새로운 값을 추가하지않고 고정된 상수값을 사용할 때 해당 ordinal값을 사용하는 것을 추천합니다. 


멤버 추가 및 메서드 추가 하기

멤버 변수와 메서드는 열거형(enum)의 각 상수에 대해 개별적으로 존재하며, 상수마다 독립적으로 값을 가지고 있습니다. 열거형 상수는 해당 열거형 타입의 인스턴스로 간주되기 때문에, 멤버 변수와 메서드는 상수의 인스턴스에 대해 호출되거나 참조될 수 있습니다.

 

아래는 열거형 클래스에 멤버 변수와 메서드를 추가한 코드입니다. 

enum DayOfWeek {
  MONDAY("Monday", 1),
  TUESDAY("Tuesday", 2),
  WEDNESDAY("Wednesday", 3),
  THURSDAY("Thursday", 4),
  FRIDAY("Friday", 5),
  SATURDAY("Saturday", 6),
  SUNDAY("Sunday", 7);

  private final String displayName;
  private final int numericValue;

  DayOfWeek(String displayName, int numericValue) {
    this.displayName = displayName;
    this.numericValue = numericValue;
  }

  public String getDisplayName() {
    return displayName;
  }

  public int getNumericValue() {
    return numericValue;
  }
}

현재 열거형 클래스 내부에 매개 변수가 있는 생서자 메서드를 생성 하였지만 외부에서 해당 생성자를 호출을 하게 되면 에러가 발생하게 됩니다. 그러한 이유는 기본적으로 private 접근자를 지정하고 있기 때문입니다. 

 

아래는 해당 한 멤버 변수와 메서드를 출력하는 코드입니다. 

public class Main {
  public static void main(String[] args) {
    DayOfWeek day = DayOfWeek.WEDNESDAY;

    // displayName 값 출력
    System.out.println("Display name of WEDNESDAY: " + day.getDisplayName());

    // numericValue 값 출력
    System.out.println("Numeric value of WEDNESDAY: " + day.getNumericValue());

    // 모든 열거형 상수의 displayName 값과 numericValue 값 출력
    for (DayOfWeek d : DayOfWeek.values()) {
      System.out.println(d + " - Display name: " + d.getDisplayName() + ", Numeric value: " + d.getNumericValue());
    }
  }
}

위의 예시에서는 DayOfWeek 열거형을 사용하여 다음과 같은 작업을 수행합니다.

  1. day 변수에 DayOfWeek.WEDNESDAY를 할당합니다.
  2. day.getDisplayName()을 호출하여 WEDNESDAY의 displayName 값을 가져와 출력합니다.
  3. day.getNumericValue()를 호출하여 WEDNESDAY의 numericValue 값을 가져와 출력합니다.
  4. DayOfWeek.values()를 사용하여 모든 열거형 상수를 순회하며, 각 상수의 displayName 값과 numericValue 값을 출력합니다.

위의 코드를 실행하면 다음과 같은 결과가 출력됩니다.

Display name of WEDNESDAY: Wednesday
Numeric value of WEDNESDAY: 3
MONDAY - Display name: Monday, Numeric value: 1
TUESDAY - Display name: Tuesday, Numeric value: 2
WEDNESDAY - Display name: Wednesday, Numeric value: 3
THURSDAY - Display name: Thursday, Numeric value: 4
FRIDAY - Display name: Friday, Numeric value: 5
SATURDAY - Display name: Saturday, Numeric value: 6
SUNDAY - Display name: Sunday, Numeric value: 7

주말인지 체크 해주는 메서드를 추가 하면 아래와 같은 코드를 작성하게 됩니다. 

public enum DayOfWeek {
  MONDAY,
  TUESDAY,
  WEDNESDAY,
  THURSDAY,
  FRIDAY,
  SATURDAY,
  SUNDAY;

  // 추가적인 메서드나 속성을 정의할 수도 있습니다
  public boolean isWeekend() {
    return this == SATURDAY || this == SUNDAY;
  }
}

위의 예시에서는 isWeekend() 메서드를 추가로 정의하여 주말인지를 확인하는 기능을 추가했습니다. 이 메서드는 현재 상수가 "SATURDAY" 또는 "SUNDAY"인지 확인하고, 그에 따라 true 또는 false를 반환합니다.


값 비교

열거형(enum) 클래스에서는 열거형 상수 간의 비교를 위해 다양한 방법을 제공합니다. 열거형 상수를 비교하는 방법은 다음과 같습니다:

 

  • == 연산자: 열거형 상수는 유일한 인스턴스이므로 == 연산자를 사용하여 동등성 비교를 할 수 있습니다. 예를 들어, DayOfWeek.MONDAY == DayOfWeek.MONDAY는 true를 반환합니다.
  • equals() 메서드: equals() 메서드를 사용하여 열거형 상수를 비교할 수도 있습니다. equals() 메서드는 Object 클래스의 메서드이므로, 재정의되어야 합니다. 하지만 자바에서는 열거형 클래스의 equals() 메서드가 이미 상수 간의 동등성 비교에 사용되도록 재정의되어 있습니다. 예를 들어, DayOfWeek.MONDAY.equals(DayOfWeek.MONDAY)는 true를 반환합니다
  • compareTo() 메서드: compareTo() 메서드를 사용하여 열거형 상수의 순서를 비교할 수 있습니다. 이 메서드는 Comparable 인터페이스의 일부로 제공되며, 열거형 상수는 기본적으로 순서를 가지기 때문에 compareTo() 메서드를 사용하여 비교할 수 있습니다. 예를 들어, DayOfWeek.MONDAY.compareTo(DayOfWeek.TUESDAY)는 -1을 반환하며, DayOfWeek.TUESDAY.compareTo(DayOfWeek.MONDAY)는 1을 반환합니다.

 

아래는 열거형 상수 비교를 보여주는 예시 코드입니다.

public class Main {
  public static void main(String[] args) {
    DayOfWeek day1 = DayOfWeek.MONDAY;
    DayOfWeek day2 = DayOfWeek.TUESDAY;

    // 동등성 비교
    System.out.println(day1 == day2); // false

    // equals() 메서드 사용
    System.out.println(day1.equals(day2)); // false

    // compareTo() 메서드 사용
    System.out.println(day1.compareTo(day2)); // -1
    System.out.println(day2.compareTo(day1)); // 1
  }
}

열거형의 장점

상수 그룹화: 열거형 클래스는 관련된 상수들을 그룹화하여 표현할 수 있습니다. 예를 들어, 요일을 열거형 클래스로 표현하면 MONDAY, TUESDAY, WEDNESDAY 등과 같은 상수들을 한 곳에서 관리할 수 있습니다. 이는 코드의 가독성과 유지보수성을 향상시키고, 실수로 잘못된 값이 사용되는 것을 방지할 수 있습니다.

 

타입 안전성: 열거형 클래스는 자바의 타입 시스템과 함께 작동하여 타입 안전성을 제공합니다. 열거형은 컴파일 타임에 타입 체크를 받기 때문에, 잘못된 값이나 다른 타입의 값이 사용되는 것을 방지할 수 있습니다. 이는 런타임 에러를 사전에 방지하고 코드의 신뢰성을 높이는 데 도움을 줍니다.

 

코드 가독성: 열거형 클래스는 가독성을 향상시킵니다. 코드에서 명시적인 상수 값을 사용하는 것보다 의미 있는 이름으로 상수를 참조할 수 있습니다. 이는 코드를 이해하고 유지보수하기 쉽게 만들어줍니다.

 

추가 기능과 메서드: 열거형 클래스는 각각의 상수에 대해 추가적인 기능과 메서드를 정의할 수 있습니다. 이는 각 상수의 특성에 맞게 동작을 추가할 수 있다는 장점을 제공합니다. 예를 들어, 요일을 열거형 클래스로 표현할 때 주말 여부를 확인하는 isWeekend()와 같은 메서드를 추가할 수 있습니다.

 

스위치 문 대체: 열거형 클래스는 스위치 문을 대체하는 데 유용합니다. 스위치 문은 상수에 대한 다양한 동작을 처리할 때 사용됩니다. 열거형을 사용하면 스위치 문보다 가독성이 높고 유연한 코드를 작성할 수 있습니다.


JVM이 인식하는 방법

열거형 클래스에 데이터를 입력하면 JVM(Java Virtual Machine)은 컴파일 시에 해당 데이터를 인식합니다. 열거형은 컴파일 시에 클래스로 변환되며, 열거형 상수는 해당 클래스의 인스턴스로 생성됩니다.

 

JVM은 열거형 클래스의 정의를 분석하여 다음과 같은 작업을 수행합니다

 

열거형 상수 생성

열거형 상수는 해당 클래스의 정의에 따라 컴파일 시에 생성됩니다.

열거형 상수는 열거형 클래스의 인스턴스로 간주됩니다.

 

멤버 변수 및 초기화

열거형 상수의 멤버 변수는 해당 상수에 정의된 값으로 초기화됩니다.

멤버 변수는 상수의 인스턴스 변수로 존재하며, 상수마다 고유의 값을 가집니다.

 

메서드 생성

열거형 클래스에 정의된 메서드는 컴파일 시에 해당 상수에 대한 메서드로 생성됩니다.

각 상수는 해당 클래스의 메서드를 호출할 수 있습니다.

 

즉, 열거형 클래스의 데이터는 컴파일 시에 클래스 파일에 포함되며, JVM은 해당 클래스 파일을 로드하여 열거형 상수를 생성하고 초기화합니다. 이후 프로그램 실행 중에는 열거형 상수를 사용할 수 있습니다.

 

주의할 점

열거형은 열거형 상수를 상수 풀에 생성하는 것이 아니라, 열거형 상수 자체가 열거형 클래스의 인스턴스입니다.

 

상수 풀(Constant Pool)은 일반적으로 문자열 상수, 정수 상수, 부동 소수점 상수 등과 같은 리터럴 상수들을 저장하는 JVM의 메모리 영역입니다. 하지만 열거형 상수는 열거형 클래스의 인스턴스로 처리되기 때문에 상수 풀에 저장되는 것이 아니라, 별도의 인스턴스로 생성됩니다.

'Language > Java' 카테고리의 다른 글

Optional<T>  (0) 2023.05.18
스트림(Stream)  (0) 2023.05.18
리플렉션(Reflection)  (0) 2023.05.11
제네릭스<Generics>  (0) 2023.05.03
Collections Framework  (0) 2023.04.26