Backend/Java

[Java]Enum(열거형)

해로몬 2024. 10. 31. 17:58

Enum

정의 : 열거형 enum 키워드를 사용해 정의하며, 여러 상수를 모아 하나의 데이터 타입으로 표현할 수 있다.
예시 ➡️ 요일 : 월,화,수,목,금,토,일
             계절 : 봄, 여름, 가을, 겨울
             주사위 : 1,2,3,4,5,6

 

Enum 메모리 구조

  • 메서드 영역: Week라는 Enum 클래스에 포함된 상수들은 Week.class 파일이 메서드 영역에 로드되면서 함께 생성됩니다. Enum 상수는 각 상수에 대한 **고유의 참조(포인터)**를 가지고 있으며, MONDAY와 SUNDAY 같은 Enum 상수들이 메서드 영역에 존재하게 됩니다.
  • 힙 영역: Enum 상수들은 메서드 영역에 로드된 참조를 통해 힙(heap) 영역에 객체로 생성됩니다. 힙 영역의 Week 객체는 메서드 영역의 상수 참조를 통해 접근할 수 있으며, Week.MONDAY, Week.SUNDAY와 같은 상수들이 실제 힙 영역에 존재하는 Enum 객체를 가리키게 됩니다.

이 구조 덕분에 Enum 상수는 **싱글톤(Singleton)**으로 관리됩니다. 즉, 동일한 상수에 대해 하나의 인스턴스만 존재하며 메모리 효율성이 높습니다.

 

Enum의 등장 배경

과거에는 상수를 어떻게 정의하였을까?

  • final 상수
  • 인터페이스 상수
  • 자체 클래스

 

1. 상수값을 int로 정의하기

가장 기초적인 방법으로는 int 타입의 상수를 정의하는 방식이 있습니다.

public class Days {
    public static final int MONDAY = 1;
    public static final int TUESDAY = 2;
    public static final int WEDNESDAY = 3;
    // 나머지 요일도 정의
}

[문제점]

  • 타입 안전성 부족: int 타입 상수는 다른 int 값들과 구분이 어려워, 실수로 잘못된 값이 들어와도 컴파일러에서 오류를 잡아내지 못합니다.
  • 가독성 저하: 숫자 1, 2, 3으로 요일을 표현하면, 이를 해석하기 어렵고 코드 가독성이 떨어집니다.
  • 확장성 한계: 새로운 상수를 추가하거나 관리하기 어려우며, 상수값이 중복될 가능성이 있습니다.

 

2. 상수 인터페이스 사용하기

다음 단계로는 상수를 담은 인터페이스를 사용하는 방법입니다. 이 방식은 여러 상수를 하나의 인터페이스로 모아 관리하며, 클래스에서 이를 구현하거나 쉽게 참조할 수 있습니다.

public interface Days {
    int MONDAY = 1;
    int TUESDAY = 2;
    int WEDNESDAY = 3;
    // 나머지 요일도 정의
}

public interface Months {
    int JANUARY = 1;
    int FEBRUARY = 2;
    // 나머지 월도 정의
}

[문제점]

  • 코드 중복 문제: 상수 집합마다 인터페이스를 별도로 정의해야 하고, 상수 그룹(예: 요일과 월)이 증가할수록 관리해야 할 인터페이스가 늘어납니다.
  • 의미 부족: int 값의 의미가 명확하지 않고, 상수값이 겹칠 경우(MONDAY와 JANUARY가 둘 다 1인 경우) 혼란을 초래할 수 있습니다.
  • 설계 원칙 위배: 인터페이스는 행동(메서드)을 정의하기 위한 용도로 설계되었기 때문에, 단순히 상수만 담는 용도로 사용하면 인터페이스의 본래 목적과 어긋납니다.

 

3. Enum 사용하기

위의 문제를 해결하기 위해 자바 1.5부터 Enum(열거형)이 도입되었습니다. Enum은 상수를 관리하는 새로운 방식으로, 타입 안전성을 보장하면서도 코드의 가독성과 유지보수성을 높입니다.

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

public enum Month {
    JANUARY,
    FEBRUARY,
    MARCH,
    // 나머지 월도 정의
}

[장점]

  • 타입 안전성 보장: Week.MONDAY와 같이 명확하게 사용되기 때문에 다른 Enum 타입이나 잘못된 값을 넣는 실수를 방지할 수 있습니다.
  • 가독성 향상: Week.MONDAY처럼 읽기 쉬운 표현이 가능하여, 코드의 가독성이 크게 향상됩니다.
  • 추가 기능 지원: Enum은 ordinal(), name(), values() 등의 메서드를 제공하여 열거형 상수의 순서나 이름을 쉽게 확인할 수 있습니다.
  • 상수별 메서드 정의 가능: 각 열거형 상수에 메서드를 정의하여, 열거형을 객체처럼 활용할 수도 있습니다.



  • 스택 영역: today라는 변수는 스택 영역에 위치하고, 이는 Week Enum 상수들을 담은 배열을 참조하고 있습니다. today 변수는 힙 영역에 저장된 각 Enum 상수를 참조하고 있습니다.
  • 힙 영역: today 변수는힙 영역에 위치한 Enum 상수 객체들(Week.MONDAY, Week.SUNDAY 등)을 가리킵니다.
  •  

Enum 기본문법

Enum 선언

열거 타입은 상수 데이터들의 집합. 따라서 배열처럼 나열하여 표현하면 됩니다.

enum Week{
	MONDAY,
    TUESDAY,
    WEDNESDAY,
    THURSDAY,
    FRIDAY,
    SATURDAY,
    SUNDAY
}
enum Season{
	Spring,
    Summer,
    Autumn,
    Winter
}

 

enum LoginResult{
	LOGIN_SUCCESS,
   	LOGIN_FAILED
}

Enum 메소드 종류

java.lang.Enum

메소드 설명 리턴타입
name() 열거 객체의 문자열을 리턴 String
ordinal() 열거 객체의 순번(0부터 시작)을 리턴 int
compareTo() 열거 객체를 비교해서 순번 차이를 리턴 int
valueOf(String name) 문자열을 입력받아서 일치하는 열거 객체를 리턴 enum
values() 모든 열거 객체들을 배열로 리턴 enum[]

 

Enum 클래스

java.lang.Enum 클래스도 Object 클래스를 자동 상속해서, enum에서도 Object 클래스의 메소드를 그대로 사용이 가능하다.

하지만 Enum 클래스는 개발자들이 Object 클래스 중 다음 4개의 메소드를 오버라이딩하지 못하도록 메소드를 final 화 하여 막아놓았다. 왜냐하면 enum은 고유한 상수이기 때문에 오버라이딩해서 자기 마음대로 바꿔버리면 고유성이 깨지기 때문이다.

메소드 내용
clone() 객체를 복제하기 위한 메소드 
(하지만 enum클래스에서 사용하면 안됨.
만약 호출될 경우 CloneNotSupportedException 이라는 예외를 발생시킴)
finalize() GC가 발생할 때 처리하기 위한 메소드
hashCode() int 타입의 해시 코드 값을 리턴하는 메소드
equals()  두 개의 객체가 동일한지 확인하는 메소드

 

 

예제 코드

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

    // 열거형 생성자 - 각 열거 상수 초기화 시 호출
    Week() {
        System.out.println("생성자 호출");
    }
}

package com.exam;

public class EnumEx01 {
    public static void main(String[] args) {
        // Week 열거형의 상수 MONDAY를 참조
        Week monday = Week.MONDAY;

        // 열거형 상수의 이름 출력
        System.out.println(monday); // MONDAY 출력
        System.out.println(Week.MONDAY); // MONDAY 출력

        // 열거형 생성자 호출은 각 열거 상수가 처음 참조될 때 한 번씩 호출됨.
        // 출력 시 각 상수별 생성자가 호출되며 "생성자 호출"이 출력됨.
        // 즉, 열거형 상수 MONDAY에 처음 접근할 때 생성자 호출 메시지가 출력됨.

        // name() 메서드: 열거형 상수의 이름을 문자열로 반환
        String name = monday.name();
        System.out.println("name = " + name);

        // ordinal() 메서드: 열거형 상수의 순서(index)를 반환
        Week friday = Week.FRIDAY;
        int weekNum = monday.ordinal();
        System.out.println("weekNum = " + weekNum); // 0 출력 (MONDAY의 순서)
        weekNum = friday.ordinal();
        System.out.println("weekNum = " + weekNum); // 4 출력 (FRIDAY의 순서)

        // compareTo() 메서드: 열거형 상수 간 순서 비교
        Week day1 = Week.MONDAY;
        Week day2 = Week.FRIDAY;
        int result1 = day1.compareTo(day2);
        int result2 = day2.compareTo(day1);
        System.out.println("result1 = " + result1); // 음수 출력 (MONDAY가 FRIDAY보다 앞에 위치)
        System.out.println("result2 = " + result2); // 양수 출력 (FRIDAY가 MONDAY보다 뒤에 위치)

        // valueOf() 메서드: 문자열로 열거형 상수를 가져옴
        Week day = Week.valueOf("SUNDAY");
        System.out.println(day); // SUNDAY 출력

        // values() 메서드: 모든 열거형 상수를 배열로 반환
        Week[] days = Week.values();
        for (Week week : days) {
            System.out.println(week); // 각 요일 상수를 출력
        }
    }
}

 



[참고]

https://inpa.tistory.com/entry/JAVA-☕-열거형Enum-타입-문법-활용-정리 [Inpa Dev 👨‍💻:티스토리]

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

공유 자원의 문제와 동기화  (0) 2024.11.01
[Java]Thread  (0) 2024.11.01
[Java] 커넥션 풀  (0) 2024.10.31
[Java] 중첩클래스  (0) 2024.10.31
[Java]Java IO(Exception/throw/File/스트림)  (0) 2024.10.24