enum (열거형)
열거형이란 상수를 정의한 타입이다. 예를 들어 계절이라는 열거형 타입은 SPRING, SUMMER, FALL, WINTER라는 4개의 상수와 그 상수에 해당하는 값을 정의한다. 계절 외에도 성별, 트럼프 카드, 결제 수단 등 제한된 범위의 상수를 표현할 데이터 타입을 찾고 있다면 enum을 사용하도록 하자. 열거형의 장점으로 다음 2가지가 있다.
- 상수의 의미가 바로 와닿는다. 코드 상의 Gender.MALE, Gender.FEMALE이라는 상수는 각각 성별의 남자와 여자를 나타낸다는 것을 쉽게 알 수 있다.
- 상수 값을 쉽게 바꿀 수 있다. 열거형의 정의만 바꿔주면 되어 코드는 변하지 않는다.
enum 정의와 사용
아래는 열거형을 정의하는 기본 코드다.
enum Direction { EAST, SOUTH, WEST, NORTH }
열거형에 정의된 상수는 열거형이름.상수명으로 사용할 수 있으며 열거형 상수간의 비교에는 '==' 연산자를 사용할 수 있다. 단 '<', '>'와 같은 비교연산자는 사용할 수 없고 compareTo 메서드는 사용가능하다. 열거형 상수 비교 시 타입을 맞춰야한다. 즉 같은 타입의 열거형 상수만 비교할 수 있으며 이로 인해 상수 또한 타입 안전성(Type Safe)이 보장되도록 만든다.
import java.lang.*;
public class Solution {
public static void main(String[] args) {
//1.
System.out.println(Gender.MALE == Gender.FEMALE);
//2.
Gender gender = Gender.MALE;
System.out.println(gender == Gender.FEMALE);
//3.
//System.out.println(Gender.MALE == Season.WINTER); 컴파일 에러
}
}
enum Gender {
MALE, FEMALE;
}
enum Season {
SPRING, SUMMER, FALL, WINTER;
}
상수값 정의
열거형 상수에 상수 값을 정의하는 코드다.
import java.lang.*;
public class Solution {
public static void main(String[] args) {
//1.
Gender gender = Gender.MALE;
System.out.println(gender); //gender.name()으로 상수명 접근가능
System.out.println(gender.getCode());
//2.
Season season = Season.WINTER;
System.out.println(season); //season.name()으로 상수명 접근가능
System.out.println(season.getCode());
System.out.println(season.getSeasonStr());
}
}
enum Gender {
MALE(0), FEMALE(1);
private final int code;
Gender(int code) {
this.code = code;
}
public int getCode() {
return code;
}
}
enum Season {
SPRING(0, "봄"), SUMMER(5, "여름"), FALL(10, "가을"), WINTER(15, "겨울");
private final int code;
private final String seasonStr;
Season(int code, String seasonStr) {
this.code = code;
this.seasonStr = seasonStr;
}
public int getCode() {
return code;
}
public String getSeasonStr() {
return seasonStr;
}
}
열거형 상수 옆에 괄호로 상수 값을 지정하며 상수 값을 저장할 수 있는 인스턴스 변수와 생성자를 추가해야한다. 인스턴스 변수에 상수값이 저장되며 상수임을 나타내기 위해 final을 추가했다. 그리고 인스턴스 변수의 접근 제어자를 private로 설정했으므로 인스턴스 변수에 접근할 수 있는 get 메서드를 추가했다. 열거형의 생성자는 접근 제어자가 묵시적으로 private이다.
java.lang.Enum
모든 열거형은 Enum 클래스를 상속받고 있다. 아래는 Enum 클래스의 코드 중 일부분이다.
public abstract class Enum<E extends Enum<E>>
implements Comparable<E>, Serializable {
private final String name;
public final String name() {
return name;
}
private final int ordinal;
public final int ordinal() {
return ordinal;
}
protected Enum(String name, int ordinal) {
this.name = name;
this.ordinal = ordinal;
}
public String toString() {
return name;
}
public final boolean equals(Object other) {
return this==other;
}
public final int compareTo(E o) {
Enum<?> other = (Enum<?>)o;
Enum<E> self = this;
if (self.getClass() != other.getClass() && // optimization
self.getDeclaringClass() != other.getDeclaringClass())
throw new ClassCastException();
return self.ordinal - other.ordinal;
}
@SuppressWarnings("unchecked")
public final Class<E> getDeclaringClass() {
Class<?> clazz = getClass();
Class<?> zuper = clazz.getSuperclass();
return (zuper == Enum.class) ? (Class<E>)clazz : (Class<E>)zuper;
}
public static <T extends Enum<T>> T valueOf(Class<T> enumType,
String name) {
T result = enumType.enumConstantDirectory().get(name);
if (result != null)
return result;
if (name == null)
throw new NullPointerException("Name is null");
throw new IllegalArgumentException(
"No enum constant " + enumType.getCanonicalName() + "." + name);
}
}
내부적으로 name와 ordinal 변수를 가지고 있다. name은 열거형 상수의 문자열 값이며 ordinal은 열거형 상수가 정의된 순서이다. (0부터 시작한다.) 이밖에도 valueOf, getDeclaringClass() 등 여러 메서드가 있다. 추가적으로 아래 메서드를 컴파일러가 자동으로 추가한다.
static E values()
static E valueOf(String name)
values 메서드는 열거형에 정의된 모든 열거형 상수를 담은 배열을 리턴하며 valueOf는 파라미터 name과 일치하는 열거형 상수를 리턴한다.
import java.lang.*;
public class Solution {
public static void main(String[] args) {
Season[] seasonArr = Season.values();
for(Season season : seasonArr) {
System.out.println(season);
System.out.println(season == Season.valueOf("WINTER")); //(season == Season.WINTER)와 같다.
}
}
}
enum Gender {
MALE(0), FEMALE(1);
private final int code;
Gender(int code) {
this.code = code;
}
public int getCode() {
return code;
}
}
enum Season {
SPRING(0, "봄"), SUMMER(5, "여름"), FALL(10, "가을"), WINTER(15, "겨울");
private final int code;
private final String seasonStr;
Season(int code, String seasonStr) {
this.code = code;
this.seasonStr = seasonStr;
}
public int getCode() {
return code;
}
public String getSeasonStr() {
return seasonStr;
}
}
열거형의 이해
자바의 정석 책을 보면 열거형 상수 하나하나가 객체라고 설명한다. 예를 들어 위의 Season 열거형을 클래스로 표현하면 아래와 같다.
class Season {
private static int id = 0;
public static final Season SPRING = new Season("SPRING",0, "봄");
public static final Season SUMMER = new Season("SUMMER", 5, "여름");
public static final Season FALL = new Season("FALL", 10, "가을");
public static final Season WINTER = new Season("SPRING", 15, "겨울");
private final String name;
private final int ordinal;
private final int code;
private final String seasonStr;
private Season(String name, int code, String seasonStr) {
this.name = name;
this.ordinal = id++;
this.code = code;
this.seasonStr = seasonStr;
}
public int getCode() { return code; }
public String getSeasonStr() { return seasonStr; }
}
싱글톤 패턴을 적용해 프로그램에서 단 하나의 인스턴스만 존재하도록 만들었으며 인스턴스 변수는 final로 설정되어 값이 바뀌지 않는다. 이럼으로써 Season의 SPRING, SUMMER, FALL, WINTER은 객체이지만 동시에 상수로 취급될 수 있다. enum의 동작 방식도 이와 유사하기에 생성자의 접근제어자도 private이며 열거형 상수간의 '==' 연산이 가능하다. 주소값이 같으면 같은 열거형 상수이기 때문이다.
'Java' 카테고리의 다른 글
Java Interface (0) | 2023.07.27 |
---|