JAVA/about java

[java] 열거타입 enum

dev_rosieposie 2023. 8. 30. 20:10

 

Goal

  1. enum 대해 알아본다
  2. enum 메모리 저장방식
  3. enum 내부 동작원리
  4. enum 객체의 메소드
  5. enum 필드

 enum 이란  ?

enum은 서로 관련있는 상수들을 하나의 그룹으로 묶어서 사용하는 자료형이다. 예로, 계절에 대한 데이터는 봄, 여름, 가을, 겨울이라는 네 개의 값만을 가진다. 이와 같이 한정된 값만을 갖는 데이터 타입이 열거타입이다.

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

enum을 사용하는 이유

  • enum을 사용하면 상수들을 의미 있는 이름으로 사용할 수 있고, 의도하지 않은 값의 입력을 방지할 수 있다.
  • 또한, 코드의 가독성을 높일 수 있다.

열거 타입과 열거 상수

public class EnumWeekExample {

    public static void main(String[] args){
        Week today = null;

        Calendar cal = Calendar.getInstance();
        int week = cal.get(Calendar.DAY_OF_WEEK);

        switch (week){
            case 1 :
                today = Week.SUNDAY; break;
            case 2 :
                today = Week.MONDAY; break;
            case 3 :
                today = Week.TUESDAY; break;
            case 4 :
                today = Week.WEDNESDAY; break;
            case 5 :
                today = Week.THURSDAY; break;
            case 6 :
                today = Week.FRIDAY; break;
            case 7 :
                today = Week.SATURDAY; break;
        }

        System.out.println("오늘 요일: "+ today);

        if(today == Week.SUNDAY){
            System.out.println("일요일에는 놉니다");
        }else{
            System.out.println("열심히 자바 공부합니다");
        }
    }
}

결과

오늘 요일: WEDNESDAY
열심히 자바 공부합니다

 enum 메모리 저장 방식 

Method Area 모든 스레드에서 공유하는 메모리 영역으로, 클래스 파일에서 읽은 정보를 저장하는 영역.
클래스의 정보(이름, 메소드, 변수 등)를 저장
  • 자바 enum은 클래스로 컴파일되어, 상수 하나당 인스턴스를 하나씩 만들어 public static final 필드로 공개한다.
  • enum 인스턴스는 클라이언트가 직접 생성할 수 없고, 인스턴스는 런타임시 단 한번만 생성됨 = 싱글턴 보장
    • enum 상수를 사용할 때마다 새로운 인스턴스를 생성하지 않고 같은 인스턴스를 참조한다
  • enum 상수들은 enum 정의 시점에 생성됨
  • enum 인스턴스는 일반적인 객체와 마찬가지로 heap 메모리에 생성
Week week1 = Week.SATURDAY;
Week week2 = Week.SATURDAY;

System.out.println(week1==week2);

결과

true

 

참고

 

[JVM] JVM 메모리모델

Goal JVM의 실행과정과 구조를 알아본다 JAVA7까지의 메모리모델과 JAV8이후의 메모리모델의 차이점을 알아본다 JVM 이란 ? JVM(Java Virtual Machine)은 자바 가상 머신을 의미하며, 자바 언어를 실행하기

dev-rosiepoise.tistory.com

 내부 동작 원리 

public abstract class Enum<E extends Enum<E>>
        implements Comparable<E>, Serializable {
    /**
     * The name of this enum constant, as declared in the enum declaration.
     */
    private final String name;

    /**
     * The ordinal of this enumeration constant (its position
     * in the enum declaration, where the initial constant is assigned
     * an ordinal of zero).
     */
    private final int ordinal;

    /**
     * Sole constructor.  Programmers cannot invoke this constructor.
     * It is for use by code emitted by the compiler in response to
     * enum type declarations.
     *
     * @param name - The name of this enum constant, which is the identifier
     *               used to declare it.
     * @param ordinal - The ordinal of this enumeration constant (its position
     *         in the enum declaration, where the initial constant is assigned
     *         an ordinal of zero).
     */
    protected Enum(String name, int ordinal) {
        this.name = name;
        this.ordinal = ordinal;
    }
    // ...
}
  • protect Enum(String name, int ordinal) 라는 부모 생성자가 있으며, name은 상수 이름, ordinal은 상수가 선언된 순서로 0부터 증가하는 구조
  • enum 클래스의 부모는 java.lang.Enum
  • 클래스의 최상위 부모클래스는 Object
    • 객체 동등 비교를 위해, equals()와 hashcode(), toString()은 오버라이딩이 가능하지만, clone()이나 finalize()는 불가

  • 자바의 enum은 Enum 클래스를 직접 상속하는 것이 아니라, 컴파일러가 컴파일 과정에서 Enum 클래스를 상속받도록 처리됨

 열거 객체의 메소드 

name() 

열거 객체가 가진 문자열 리턴

// 열거 변수에 열거 상수 저장하기
Week today = Week.THURSDAY;

String name = today.name();
System.out.println(name);

결과 

THURSDAY

 

ordinal() 

열거 객체 중 몇 번째 열거 객체인지 알려준다. 열거 객체의 순번은 타입을 정의할 때 주어진 순번을 말하는데, 0번부터 시작한다.

int ordinal = today.ordinal();
System.out.println(ordinal);

결과

3

 

compareTo() 

매개값으로 주어진 열거 객체를 기준으로 전후로 몇 번째 위치하는지를 비교 - 상대적 위치를 비교

Week day1 = Week.MONDAY;
Week day2 = Week.SATURDAY;

int result1 = day1.compareTo(day2);
int result2 = day2.compareTo(day1);

System.out.println(result1);
System.out.println(result2);

결과

-5   // day2를 기준으로 day1의 상대적 위치 리턴

5    // day1을 기준으로 day2의 상대적 위치 리턴

 

valueOf() 

매개값으로 주어지는 문자열과 동일한 문자열을 가지는 열거 객체를 리턴한다. 

Week day1 = Week.MONDAY;
Week weekDay = Week.valueOf("MONDAY");

System.out.println(weekDay);
System.out.println(day1 == weekDay);

MONDAY
true

 

values() 

매개값으로 주어지는 문자열과 동일한 문자열을 가지는 열거 객체 리턴

Week[] days = Week.values();
for(Week day : days){
    System.out.println(day);
}

 

결과

MONDAY
TUESDAY
WEDNESDAY
THURSDAY
FRIDAY
SATURDAY
SUNDAY

 

=> 배열의 인덱스는 열거 객체의 순번과 같고, 각 인덱스 값은 해당 순번의 열거 객체 번지다.

 

 열거 타입 필드 

열거 타입의 열거 객체도 인스턴스이므로 인스턴스 필드를 가질 수 있다. 이를 통해 상수와 연관된 추가적인 데이터를 상수 자체에 포함하여 관리할 수 있다. 일반적인 인스턴스 필드를 사용하는 것 처럼, 인스턴스 필드를 명시하고 생성자를 정의하면 된다. 이때, 각 열거 객체의 필드는 상수 이름 옆에 괄호 () 를 사용하여 적어준다.

public enum Week {
    MONDAY("월요일", "月"),
    TUESDAY("화요일", "火"),
    WEDNESDAY("수요일", "水"),
    THURSDAY("목요일", "木"),
    FRIDAY("금요일", "金"),
    SATURDAY("토요일", "土"),
    SUNDAY("일요일", "日");

    public String korean;

    public String chinese;

    Week(String korean, String chinese) {
        this.korean = korean;
        this.chinese = chinese;
    }
}

문제

그런데 현재 모든 필드가 public 으로 열려있어 캡슐화가 되어 있지 않은 상태이다. 이렇게 된다면 아래와 같이 인스턴스 필드를 직접 수정할 수 있다.

for (Week day : days) {
    System.out.println(day.korean + " (" + day.chinese + ")");
}

Week.SATURDAY.korean = "변경된다";
System.out.println(Week.SATURDAY.korean);

결과

월요일 (月)
화요일 (火)
수요일 (水)
목요일 (木)
금요일 (金)
토요일 (土)
일요일 (日)
변경된다

 

해결

열거 타입도 일반 클래스와 마찬가지로 메소드를 지원한다. 필드를 private 으로 닫고, 게터(Getter) 만을 제공해보자.

private String korean;

private String chinese;

Week(String korean, String chinese) {
    this.korean = korean;
    this.chinese = chinese;
}

public String getKorean() {
    return korean;
}
public String getChinese() {
    return chinese;
}
for (Week day : days) {
    System.out.println(day.getKorean() + " (" + day.getChinese() + ")");
}

System.out.println(Week.SATURDAY.getKorean());

결과

월요일 (月)
화요일 (火)
수요일 (水)
목요일 (木)
금요일 (金)
토요일 (土)
일요일 (日)
토요일

 

 

참고

이것이 자바다 by 신용권

https://hudi.blog/java-enum/

https://velog.io/@wlsgur1533/Java-Enum%EC%9D%B4%EB%9E%80