[Day 14 | Java] Enum 열거형

y♡ding·2024년 10월 31일
0

데브코스 TIL

목록 보기
94/163

Enum(열거형)은 자바에서 서로 연관된 상수들을 하나의 집합으로 정의하는 특별한 데이터 타입입니다. 열거형은 일반적으로 일정한 값들 중 하나를 선택해야 할 때 유용하며, 코드의 가독성과 안전성을 높여줍니다.

Enum (Java SE 17 & JDK 17)

Enum 기본 개념

  • 정의: 열거형은 enum 키워드를 사용해 정의하며, 여러 상수를 모아 하나의 데이터 타입으로 표현할 수 있습니다.
  • 사용 예: 요일, 색상, 방향 등 고정된 선택지가 있는 값을 사용할 때 적합합니다.
  • 상수 정의: 각 열거형 상수는 대문자로 작성하며, 쉼표로 구분합니다.

예시

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

Enum의 메모리 구조

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

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


Enum의 등장 배경

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 값의 의미가 명확하지 않고, 상수값이 겹칠 경우(MONDAYJANUARY가 둘 다 1인 경우) 혼란을 초래할 수 있습니다.
  • 설계 원칙 위배: 인터페이스는 행동(메서드)을 정의하기 위한 용도로 설계되었기 때문에, 단순히 상수만 담는 용도로 사용하면 인터페이스의 본래 목적과 어긋납니다.

3. Enum 사용하기

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

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

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

Enum의 장점:

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

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

예제 코드

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); // 각 요일 상수를 출력
        }
    }
}
package com.exam;

public enum Season {
    SPRING("봄"),
    SUMMER("여름"),
    AUTUMN("가을"),
    WINTER("겨울");

    private String season; // 각 열거형 상수에 대응하는 문자열 값을 저장할 변수

    // 생성자: 열거형 상수가 처음 참조될 때 한 번씩 호출됨
    private Season(String season) {
        System.out.println("생성자 호출: " + season);
        this.season = season;
    }

    // 열거형 상수의 문자열 값을 반환하는 메서드
    public String getSeason() {
        return season;
    }
}
 package com.exam;

import java.util.Calendar;

public class EnumEx02 {
    public static void main(String[] args) {

        // Calendar.WEEK_OF_YEAR - Enum을 사용한 옵션
        Calendar calendar = Calendar.getInstance();
        int week = calendar.get(Calendar.DAY_OF_WEEK);
        System.out.println(week);
    }
}
package com.exam;

import java.util.Calendar;

public class EnumEx03 {
    public static void main(String[] args) {
        // Season 열거형의 상수 SPRING을 참조
        Season spring = Season.SPRING;

        // 열거형 상수의 이름과 설명 출력
        System.out.println(spring); // SPRING 출력
        System.out.println(spring.getSeason()); // "따뜻한 봄" 등 계절 설명 출력

        // 모든 Season 열거형 상수의 이름과 설명 출력
        for (Season season : Season.values()) {
            System.out.println("현재 계절: " + season + ", 설명: " + season.getSeason());
            // season : 현재 순회 중인 Season 열거형 상수
            // season.getSeason() : 현재 Season 상수의 설명을 반환
        }
    }
}

추가

✔️ 힙 영역에 객체가 생성된다?
enum의 각 값(상수)은 실제로 각각 하나의 객체입니다. 예를 들어, enum Week { MONDAY, TUESDAY }와 같이 선언하면 MONDAYTUESDAY는 각각 Week 클래스의 객체로 힙 영역에 생성됩니다. 이 객체들은 JVM이 실행될 때 생성되고, enum이 여러 번 호출되더라도 같은 객체가 재사용됩니다.

✔️ enum도 클래스이다! (Week → Enum → Object)
Java의 enum은 실제로 특별한 형태의 클래스입니다. 모든 enum은 기본적으로 java.lang.Enum 클래스를 상속하며, Object 클래스의 메서드를 사용할 수 있습니다. 따라서 enum의 각 상수는 Enum 클래스의 인스턴스로 취급됩니다. 예를 들어, Week라는 이름의 enum은 내부적으로 Week extends Enum<Week> 형태로 동작합니다.

✔️ 데이터 하나하나가 객체다?
enum 내에 정의된 각 상수는 enum 클래스의 객체로 취급됩니다. enum 타입을 사용할 때, 각 상수는 하나의 고유한 인스턴스가 됩니다. 예를 들어, enum Day { MONDAY, TUESDAY, WEDNESDAY }에서는 MONDAY, TUESDAY, WEDNESDAY가 모두 Day 클래스의 객체입니다.

0개의 댓글

관련 채용 정보