[Java] Enum
Enum이란?
enum(열거형)은 열거형 클래스이며, 자바 1.5부터 사용이 가능하다.
서로 관련된 상수를 편리하게 선언하기 위한 것으로, 여러 상수를 정의할 때 사용하면 유용하다.
자바의 열거형은 C언어의 열거형보다 더 향상된 것으로 열거형이 갖는 값뿐만 아니라 타입도 관리하기 때문에 보다 논리적인 오류를 줄일 수 있다.
자바 외 언어들에서는 타입이 달라도 값이 같으면 조건식 결과가 참(true)인 경우가 있으나, 자바의 열거형은 타입에 안전한 열거형(typesafe enum)이라서 실제 값이 같아도, 타입이 다르면 컴파일 에러가 발생한다.
Enum을 사용하는 이유
Enum을 잘 사용하면 코드의 가독성을 높이고 논리적인 오류를 줄일 수 있다.
학생 이름을 입력받으면 시험 점수를 알려주는 프로그램의 학생 이름을 상수로 관리한다고 했을 때의 문제점을 알아보자.
public class EnumDemo {
//A학교
private static final int KIM = 1;
private static final int NAM = 2;
private static final int PARK = 3;
//B학교
private static final int KIM = 4; //컴파일 에러
private static final int NAM = 2; //A학교 NAM과 중복
public static void main(String[] args) {
int name = KIM;
switch(name){
case KIM:
System.out.println("학생 KIM는 100점입니다.");
break;
case NAM:
System.out.println("학생 NAM는 70점입니다.");
break;
case PARK:
System.out.println("학생 PARK는 50점입니다.");
break;
}
}
}
위 코드의 문제점은 다음과 같다.
- 각 상수에 부여된 1,2,3이라는 값은 논리적으로 아무런 의미가 없다. 즉 학생 KIM와 1은 아무런 관련이 없다.
- 이름의 충돌이 생길 수 있다. 만약 프로그램의 크기가 커 저서 다른 학교의 학생들도 관리한다고 가정해보자. A라는 학교에 KIM이라느 학생이 있고 B라는 학교에도 KIM이라는 학생이 있으면 이름이 중복되기 때문에 에러가 발생한다.
- 학교가 서로 다른 학생들끼리는 시험 점수가 비교되면 안되는데 학교 A의 학생 NAM과 학교 B의 학생 NAM 모두 int형 자료형이고 상수값이 동일하기 때문에 비교가 가능하다. 애초에 비교하는 코드를 작성할 수 없게 컴파일 단계에서 막아줘야 한다.
한정된 값(학생 이름)을 Enum(열거형)으로 관리한다면 위와 같은 문제점들을 해결해주고, 더욱 간단히 선언할 수 있도록 만든다.
Enum 정의
문법
enum 열거형이름 { 상수명1, 상수명2, ... 상수명n; }
예제
enum Job { TEACHER, STUDENT; }
Enum 사용 방법
문법
열거형이름.상수이름
예제
Job.TEACHER
Enum 특징
Enum에 정의된 상수들은 해당 Enum 타입의 객체이다
C 등의 다른 언어에도 열거형이 존재한다. 하지만 다른 언어들과 달리 Java의 enum은 단순한 정수 값이 아닌 해당 enum 타입의 객체이다.
enum Job { TEACHER, STUDENT; }
위와 같이 정의된 열거형은 아래와 같이 표현할 수 있다.
class Job {
public static final Job TEACHER = new Job("TEACHER");
public static final Job STUDENT = new Job("STUDENT");
private String name;
private Job(String name) {
this.name = name;
}
}
물론 실제 Enum의 구현체와 다르지만, 이런 형태로 생각하면 이해하기 더욱 쉽다.
생성자와 메소드를 추가할 수 있다
enum Job {
TEACHER,
STUDENT;
Job(){
System.out.println(this.name() + " 생성자 호출");
}
}
public class EnumDemo {
public static void main(String[] args) {
Job student = Job.STUDENT;
}
}
TEACHER 생성자 호출
STUDENT 생성자 호출
생성자를 정의할 수 있는데, enum의 생성자의 접근제어자는 private이기 때문에 외부에서 상수를 추가할 수 없다.
열거형의 멤버 중 하나를 호출하면, 열거된 모든 상수의 객체가 생성된다. 위 예시를 보면 STUDENT 하나를 호출했는데 열거된 모든 상수의 생성자가 호출되었음을 확인할 수 있다. 상수 하나당 각각의 인스턴스가 만들어지며 모두 public static final이다.
생성자를 이용해서 상수에 데이터를 추가할 수 있다
enum Job {
DOCTOR(5000),
TEACHER(1500),
NURSE(1000);
private final int dailyWages; //일급
Job(int dailyWages){
this.dailyWages = dailyWages;
}
public int getDailyWages() {
return dailyWages;
}
}
public class EnumDemo {
public static void main(String[] args) {
System.out.println("----일급----");
System.out.println("DOCTOR : " + Job.DOCTOR.getDailyWages());
System.out.println("TEACHER : " + Job.TEACHER.getDailyWages());
System.out.println("NURSE : " + Job.NURSE.getDailyWages());
}
}
----일급----
DOCTOR : 5000
TEACHER : 1500
NURSE : 1000
메소드에 switch문을 사용해 상수에 따라 다른 로직을 실행시킬 수 있다.
public double getMonthlyWages(int day) //상수에 따라 다르게 측정되는 월급
{
switch (this) {
case DOCTOR:
return dailyWages * day * 2.5;
case TEACHER:
return dailyWages * day * 2;
case NURSE:
return dailyWages * day * 1.5;
default:
return 0;
}
}
Enum Job에 위의 메소드를 추가한 뒤 아래와 같이 출력하면
System.out.println("----월급----");
System.out.println("DOCTOR : " + Job.DOCTOR.getMonthlyWages(30));
System.out.println("TEACHER : " + Job.TEACHER.getMonthlyWages(30));
System.out.println("NURSE : " + Job.NURSE.getMonthlyWages(30));
다음과 같은 결과가 나오는 것을 확인할 수 있다.
----월급----
DOCTOR : 375000.0
TEACHER : 90000.0
NURSE : 45000.0
추상 메서드를 선언해서 위와 동일하게 구현할 수 있다.
enum Job {
DOCTOR(5000){
@Override
double getMonthlyWages(int day) {
return getDailyWages() * day * 2.5;
}
},
TEACHER(1500){
@Override
double getMonthlyWages(int day) {
return getDailyWages() * day * 2;
}
},
NURSE(1000){
@Override
double getMonthlyWages(int day) {
return getDailyWages() * day * 1.5;
}
};
private final int dailyWages; //일급
Job(int dailyWages){
this.dailyWages = dailyWages;
}
public int getDailyWages() {
return dailyWages;
}
abstract double getMonthlyWages(int day); //상수에 따라 다르게 측정되는 월급
}
Enum 상수 간의 비교가 가능하다.
열거형 상수간의 비교에는 == 을 사용할 수 있다. equals()가 아닌 == 로 비교가 가능하다는 것은 그만큼 빠른 성능을 제공한다는 뜻이다.
Job doctor = Job.DOCTOR;
if(doctor == Job.DOCTOR){
...
} else if(doctor.compareTo(Job.NURSE) > 0){
...
}
참고
'프로그래밍 언어 > Java' 카테고리의 다른 글
[Java] 동일성(identity)과 동등성(equality) (0) | 2021.12.21 |
---|---|
[Java] 오버로딩과 오버라이딩 (0) | 2021.12.21 |
[Java] Interface (0) | 2021.12.01 |
[Java] Generic (0) | 2021.11.24 |
[Java] Reflection (0) | 2021.11.21 |
댓글