Dev/Java

[Java] Enum

syuare 2025. 4. 22. 19:51

enum (열거형, eunmerated type)

  • 열거형: 서로 연관된 상수들의 집합
  • enum은 자바 1.5부터 문법적으로 지원 시작했다.
더보기

enum은 어쩌다 등장 / 탄생하게 되었을까 (enum 탄생 배경)

 

enum이 없을 때는 class 내 상수들을 주석으로 정의하였다.

*상수: 변하지 않는 값

/*
	* 1. 사과
	* 2. 복숭아
	* 3. 바나나
*/

int type = 1; // 사과를 의미

 

그런데 설명이 적힌 주석이 코드랑 멀어지거나 실수로 삭제할 경우 문제가 될 수 있다.

이걸 개선하기 위해 아래와 같이 변수 = 값으로 정의할 수 있다.

- 상수는 변하지 않는 값이기 때문에 final을 사용하여 상수화를 하였고,

- static을 통해 메모리를 한 번만 할당되도록 하였다. 

private final static int APPLE = 1;
private final static int PEACH = 2;
private final static int BANANA = 3;

 

그런데 값은 같은데, 변수명이 다를 경우가 있을 때가 있을 수 있다.

변수 명은 다르지만 변수가 가진 상수는 동일할 경우, 이것을 비교할 경우 잘못된 값이 도출될 수 있다.

 

private final static int APPLE = 1; // Fruit
private final static int GOOGLE = 1; // Company

if (APPLE == GOOGLE) // true?

 

또한 타입의 안전 역 보장할 수 없다. (APPLE는 Fruit 타입인데, GOOGLE은 Company 타입)

 

이런 경우를 방지하기 위해 변수명에 타입을 구분할 수 있는 구분자를 추가해보았다 > 네임 스페이스 기법

// fruit
private final static int FRUIT_APPLE = 1;
private final static int FRUIT_PEACH = 2;
private final static int FRUIT_BANANA = 3;
     
// company
private final static int COMPANY_GOOGLE = 1;
private final static int COMPANY_APPLE = 2;
private final static int COMPANY_ORACLE = 3;

 

이렇게 선언해도 되겠지만, 선언된 상수의 코드가 너무 복잡하다.

이럴 때 인터페이스 형식을 활용한다면 조금 더 간결하게 생성할 수 있다.

interface FRUIT{
    int APPLE=1, PEACH=2, BANANA=3;
}

interface COMPANY{
    int GOOGLE=1, APPLE=2, ORACLE=3;
}

 

그런데 여전히 문제는, 그룹이 다르더라도 변수에 선언된 상수는 동일하기 때문에 여전히 오류를 해결해주지 않는다.

또한 이 오류를 컴파일러가 찾아주지 못한다.

 

그래서 생각한 것이, 이 인터페이스를 class로하여, 클래스 변수로 인스턴스화 하여 사용하였더니 

앞서 타입이 다르지만 상수값이 동일했던 것의 오류를 해결할 수 있었다.

class Fruit{
    public static final Fruit APPLE  = new Fruit();
    public static final Fruit PEACH  = new Fruit();
    public static final Fruit BANANA = new Fruit();
}
class Company{
    public static final Company GOOGLE = new Company();
    public static final Company APPLE = new Company();
    public static final Company ORACLE = new COMPANY(Company);
}

// ---------------------------

public static void main(String[] args) {
        if(Fruit.APPLE == Company.APPLE){ // 컴파일에서 오류 발생
            System.out.println("과일 애플과 회사 애플이 같다.");
        }
    }
}

 

그런데 문제는 이것을 switch문에 활용하가 했는데, switch는 커스텀 데이트를 입력 변수로 활용할 수 없다.

그리고 클래스 변수로 선언하는데 너무 복잡하다

 

이러한 클래스의 장점을 가지면서도 문제점을 해결하고자 탄생한 것이 바로 enum 이다

 

 

예시

// 기존 형태
class Fruit{
    public static final Fruit APPLE  = new Fruit();
    public static final Fruit PEACH  = new Fruit();
    public static final Fruit BANANA = new Fruit();
}
class Company{
    public static final Company GOOGLE = new Company();
    public static final Company APPLE = new Company();
    public static final Company ORACLE = new COMPANY(Company);
}


// enum 사용 시

enum Fruit{
    APPLE, PEACH, BANANA;
}
enum Company{
    GOOGLE, APPLE, ORACLE;
}

 

enum은 class, interface와 동급의 형식을 가지는 단위

  • enum은 사실상 class이다.
  • 편의를 위해 문법적 형식을 가지고 있고, 이를 구분하기 위해 'enum' 이라는 키워드를 사용한다.

enum을 사용하는 이유

  • 코드가 짧아진다 > 간략해진다 > 단순해진다. (가독성 ↑)
  • 타입 안전
    • 잘못된 문자열을 넣을 경우 컴파일 단계에서 에러가 발생함 > 실제 프로그램 실행 때 오류 발생하 것을 방지
  • 인스턴스 생성, 상속 방지한다
    • enum은 enum명 + 변수명 = enum.요소명; 으로 사용하는 것으로 약속되어 있다.
    • 서로 연관되어 있는 상수의 집합 > 문법적 요소
    • enum을 상속한다, 인스턴스화 한다? > 의도가 아님
  • 키워드 enum을 사용함으로 써 해당 의도가 열거형임을 보여줄 수 있다.
  • switch의 변수로 사용할 수 있다.
    • switch에서 사용할 수 있는 입력변수: char , byte , short , int , Character , Byte , Short , Integer , String , enum
    • (참고)long, float, double은 입력변수로 사용할 수 없다!
      • 내부적으로 32-bit 정수에 최적화 되어 있기 때문
  • 메서드 생성 및 활용 등 단순히 타입으로 정의하는 것을 넘어 다양한 기능을 수행할 수 있다.
더보기

enum은 클래스?


enum은 생성자를 가질 수 있다

이유는 enum은 클래스이기 때문

  • 생성자를 정의할 수 있다. (예시: Fruit())
    • 상수 값이 세팅될 때 마다 Fruit이 인스턴스화가 될때마다 생성자가 호출됨 
    • Fruit()의 출력문이 3회 출력됨
enum Fruit { // 위와 같이 복잡하게 작성된 것을 enum 이란 간략한 코드로 표현할 수 있음
    APPLE, PEACH, BANANA;
    Fruit() {
        System.out.println("Call Constructor" + " - " + this);
    }
}

 

생성자 Fruit()에 매개 변수를 추가할 경우

> APPLE, PEACH, BANANA에도 매개변수가 추가되어야 한다.

enum Fruit { // 위와 같이 복잡하게 작성된 것을 enum 이란 간략한 코드로 표현할 수 있음
    APPLE("red"), PEACH("pink"), BANANA("yellow"); // APPLE에 인스턴스 변수 값인 color, red가 된다.
        
    public String color;
    
    Fruit(String color) { // 생성자 Fruit에 매개변수가 있으니 생성했던 상수(APPLE 등)에도 변수를 추가해야한다
        System.out.println("Call Constructor" + " - " + this);
        this.color = color;
        // this.color = 전역 변수 > public String color 의 color를 의미
        // color = 지역 변수 > Fruit(String color)의 color를 의미
    }
}

 

생성자를 통해 생선된 매개 변수 color도 활용할 수 있다.

enum Fruit {
    APPLE("red"), PEACH("pink"), BANANA("yellow");
    public String color;
    Fruit(String color) {
        System.out.println("Call Constructor" + " - " + this);
        this.color = color;
    }
}


public static void main(String[] args) {
        Fruit type = Fruit.APPLE;
        switch(type){ // switch에서는 class의 변수를 사용할 수 없음
            case APPLE: // Fruit의 상수만 작성해도 된다 라고 약속됨
                System.out.println(57+" kcal, color: " + Fruit.APPLE.color);
                break;
            case PEACH:
                System.out.println(34+" kcal, color: " + Fruit.PEACH.color);
                break;
            case BANANA:
                System.out.println(93+" kcal, color: " + Fruit.BANANA.color);
                break;
	}
}

 

enum에는 메서드도 생성할 수 있다.

getColor() 메서드를 생성, 활용할 수 있다

  • 예시에서 사용 > 위의 스크린샷과 동일한 값을 출력한다.
enum Fruit {
    APPLE("red"), PEACH("pink"), BANANA("yellow");
    
    private String color;
    
    public String getColor(){
        return this.color
    }
    Fruit(String color) {
        System.out.println("Call Constructor" + " - " + this);
        this.color = color;
    }
}


public static void main(String[] args) {
        Fruit type = Fruit.APPLE;
        switch(type){ // switch에서는 class의 변수를 사용할 수 없음
            case APPLE: // Fruit의 상수만 작성해도 된다 라고 약속됨
                System.out.println(57+" kcal, color: " + Fruit.APPLE.getColor());
                break;
            case PEACH:
                System.out.println(34+" kcal, color: " + Fruit.PEACH.getColor());
                break;
            case BANANA:
                System.out.println(93+" kcal, color: " + Fruit.BANANA.getColor());
                break;
	}
}

 

 

 

enum 과 클래스 (public static final ~~~ ) 의 차이점

클래스로 정의할 경우

  • 클래스가 가지고 있는 멤버(APPLE, PEACH 등)들을 배열처럼 값을 열거할 수 없다
  • Fruit 클래스 내 어떤 상수를 가지고 있는지, 어떤 데이터/값이 있는지 코드 작성자가 알고 있어야 한다.

 

enum으로 정의할 경우

  • 클래스 정의와는 다르게 멤버 전체를 배열처럼 열거할 수 있다.
enum Fruit { 
    APPLE("red"), PEACH("pink"), BANANA("yellow");
   
    private String color; 
    public String getColor(){
        return this.color;
    }
}


for(Fruit f : Fruit.values()){
	System.out.println(f+", "+f.getColor());
}

 

 


출처/참고자료

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

[Java] System.out.print의 진실 (feat. toString() Override)  (0) 2025.04.24
[Java] Generic  (0) 2025.04.23
[Java] double 형 값의 소수점 처리  (0) 2025.04.21
[Java] 배열  (0) 2025.04.18
[Java] next() vs nextLine()  (0) 2025.04.17