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 |