Java Enum이란

업데이트:
3 분 소요

Step 1: Enumeration의 이해와 정리

데이터 중에서는 요일 ( 월, 화, 수, 목, 금, 토, 일 ), 계절( 봄, 여름, 가을, 겨울) 등과 같이 몇 가지 한정된 값을 갖는 경우가 흔히 있습니다. 요일, 계절과 같이 한정된 데이터만을 가지는 타입을 Enumeration Type이라고 하며 열거타입에 들어가는 값( 월, 화 ,수 등 )들을 열거 상수( Enumeration constant)라고 합니다. JAVA는 JAVA 1.5부터 이러한 열거형 타입들을 사용할 수 있게 되었으며 enum 데이터 타입이라고 표시됩니다. 관례로 열거타입을 선언하기 위해서는 JAVA Class 명처럼 열거타입의 이름을 정하고 타입이름으로 첫 글자 대문자로 하여 .java 파일을 생성합니다. JAVA 파일 안에서 class대신 enum을 적어줍니다. 열거상수를 적을 때는 관례로 대문자로 적습니다. 만약 열거상수가 2개의 단어로 연결되어 있을 때는 _로 연결하는 것이 관례입니다.

Week.java 
public enum Week {
    MONDAY, TUSEDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY
}

Step 2: Enum과 메모리 구조

JAVA에서 열거 상수는 상수 각각을 내부적으로 public static final 필드이면서 객체로 제공되도록 합니다. static이 붙어있기 때문에 각각의 상수는 클래스변수로 클래스로더가 로드 시점에 JVM Method영역에 해당 클래스 변수들을 항상 상주시켜 프로그램이 종료되기 전에는 언제든지 가져다 쓸 수 있는 주소공간을 확보합니다.

Emum의 메모리 위치

Please Note: Emum을 호출하기 전에는 단순 공간만 확보합니다.
좀 더 JVM에 대해 자세한 부분은 JVM 포스트를 참고하시기 바랍니다.

Step 3: Enum과 메모리 초기화

이제는 사용 부를 살펴보겠습니다. 사용 부에서는 클래스의 인스턴스를 생성하는 것과 비슷하지만, new가 없는 형태입니다.

Week today = Week.MONDAY;

어떤 클래스에서든 해당 로직을 만나면 Heap영역에 Week 객체는 MONDAY부터 SUNDAY까지 각각 java.lang.Enum클래스를 상속받는 고유의 객체가 만들어지고 Method 영역의 열거상수들은 해당 Heap영역에 생성된 객체를 바라봅니다. 즉 로직을 만나는 순간 이전에 Method에 할당되었던 메모리에 Heap영영에 생긴 객체들이 할당됩니다.

Emum의 메모리 할당


today변수는 JVM Stack영역에서 사용하므로 stack영역의 today는 Method 영역에 있는 MONDAY의 객체의 주소 값을 복사하므로 today와 Week.MONDAY는 Heap에 생성된 같은 객체를 바라봅니다.

enum의 관계

이러한 이유로 today == Week.SUNDAY 로직이 같은 객체를 반환하므로 true가 성립됩니다. 같은 이유로 아래 코드가 true가 나와도 이해가 됩니다.

Week thisWeek = Week.SUNDAY;
Week nextWeek = Week.SUNDAY;
thisWeek == nextWeek // true

Step 4: Enum의 응용

열거상수 즉 열거객체들은 java.lang.Enum클래스를 상속받기 떄문에 name(), ordinal(), compareTo(), valueOf(String name), values() 메서드를 사용할 수 있습니다. 관례적으로 열거 타입을 선언하기 위해서는 열거 타입의 이름(첫 글자 대문자)을 정하고 타입이름으로 .java 파일을 생성하지만, 특정 클래스에서만 필요한 열거 타입이라면 아래와 같이 사용 가능합니다.

public class Shoes {
    public String name;
    public int size;
    public enum Type {
        WALKING, RUNNING, TRACKING, HIKING   
    }
}

enum은 class처럼 생성자를 가질 수 있지만 고정된 상수의 집합임으로 런타임이 아닌 컴파일 타임에 모든 값을 가지고 있어야 하기에 private로 선언되어야 오류가 발생하지 않습니다. 각각의 열거 상수 객체가 Heap에서 각각 생성됨으로 아래와 같은 결과가 발생합니다.

public enum Color {
    RED, GREEN, BLUE; 
    private Color() { 
        System.out.println("Constructor called for : " + this.toString()); 
    } 
}

Color color = Color.BLUE;
1
2
3
4
// 출력
Constructor called for : RED
Constructor called for : GREEN
Constructor called for : BLUE

Enum 일반 메서드

enum은 다른 추상 메서드가 아닌 일반 메서드를 가질 수 있습니다.

public enum Color {
    RED, GREEN, BLUE;

    public void colorInfo() { 
        System.out.println("Universal Color"); 
    }
}

Color.BLUE.colorInfo();
1
2
// 출력
Universal Color;

Enum 추가 속성과 생성자

열거형 상수는 추가 속성을 부여할 수 있으며 추가 속성이 여러 개가 있을 시 생성자에 순서대로 각각의 타입으로 넣을 수 있습니다.

public enum Color {

    RED("빨강",100), GREEN("초록",10), BLUE("파랑",30); 
    
    private String koreName;
    private int pay;

    // 빨강, 100 순서대로 할당된다.
    private Color(String koreName, int pay){ 
        this.koreName = koreName;
        this.pay      = pay;
    } 

    public void colorInfo(){ 
        System.out.println(koreName +"의 비용은 " + pay +"입니다."); 
    } 
}

Color.BLUE.colorInfo();
1
2
// 출력 
파랑의 비용은 30입니다.

Enum 메서드 재정의

abstract 메서드를 통해 열거형 상수안에 각 상수별로 특정 메서드를 재정의 하도록 할 수 있습니다.

public enum Color {
    RED("빨강",100) {
        @Override
        public int calc(int a, int b) {
            return a+b;
        }
    }, GREEN("초록",10) {
        @Override
        public int calc(int a, int b) {
            return a-b;
        }
    }, BLUE("파랑",30) {
        @Override
        public int calc(int a, int b) {
            return a*b;
        }
    }; 
    
    private String koreName;
    private int pay;
    private Color(String koreName, int pay){ 
        this.koreName = koreName;
        this.pay      = pay;
    } 

    public void colorInfo(){ 
        System.out.println(koreName +"의 비용은 " + pay +"입니다."); 
    } 
    
    public abstract int calc( int a, int b );
}

System.out.println(Color.BLUE.calc(5,10));


1
2
// 출력 
50

중첩 Enum

만약 enum상수끼리 공유하는 코드를 만들고 싶다면 중첩 Enum을 만들어 응용할 수 있습니다.

public enum Color {
    RED("빨강",100,CheckPay.RED ), GREEN("초록",30,CheckPay.RED), BLUE("파랑",49,CheckPay.BLUE);
    
    private String koreName;
    private int pay;
    private CheckPay checkPay;
    private Color(String koreName, int pay, CheckPay checkPay ){ 
        this.koreName = koreName;
        this.pay      = pay;
        this.checkPay = checkPay;
    } 

    
    public int calc() {
        return this.checkPay.calc(pay);
    };
    
    private enum CheckPay{
        RED {
            @Override
            public int calc(int pay) {
                return pay*100;
            }
        },BLUE{
            @Override
            public int calc(int pay) {
                return pay*50;
            }
        };
        
        public abstract int calc( int pay );
    }
}

System.out.println(Color.BLUE.calc());

1
2
// 출력 
2450

참고자료

– 이것이 자바다
https://wedul.site/285
http://woowabros.github.io/tools/2017/07/10/java-enum-uses.html
https://velog.io/@pop8682/Enum-27k067ns4a
https://www.opentutorials.org/module/1226/8025

카테고리:

업데이트:

댓글남기기