오늘은 Java Enum에 대해서 복습해보았다.
되게 신기한게 책에 밑줄이 좍좍 그어져 있는데 마치 새로 알게 된 정보처럼 느껴진다는 것이었다.
ㅠㅠ 떵뇌 인간
그렇지만 이번엔 완벽하게 기억할 것만 같은 느낌인데
책에 기억에 없는 밑줄을 그었던 순간에도 이렇게 느꼈을지도 ...
그럴지도 ...
Enum
열거형
열거형 데이터란, 서로 관련된 상수들을 묶어서 관리하는 틀 역할을 제공하는 것이다.
예를 들어서 월 화 수 목 금 토 일의 내용을 상수로 관리하고 싶다면 다음과 같이 정의한다.
// enum 열거형이름 { 상수명1, 상수명2, 상수명3, ... }
enum Day {
MONDAY,
TUESDAY,
WEDNESDAY,
THURSDAY,
FRIDAY,
SATURDAY,
SUNDAY
}
다음과 같이 사용할 수 있다.
Day monday = Day.MONDAY;
String mondayStr = monday.name(); // "MONDAY"
int mondayIdx = monDay.ordinal(); // 0
각 열거형 상수는 선언된 순서대로 0부터 시작하여 일종의 id 값을 갖게 된다.
Java에서의 열거형
열거형 상수가 단순히 정수값을 갖는 것이 아닌, 독립된 특수 클래스로서 동작한다.
예를 들어서 아래의 열거형 Day를 정의했다고 하자.
enum Day {
MONDAY,
TUESDAY,
WEDNESDAY,
THURSDAY,
FRIDAY,
SATURDAY,
SUNDAY
}
그럼 내부적으로는 아래와 유사한 구조의 클래스가 생성된다. (유사한!!!!이다)
class Day {
static final Day MONDAY = new Day("MONDAY");
static final Day TUESDAY = new Day("TUESDAY");
static final Day WEDNESDAY = new Day("WEDNESDAY");
static final Day THURSDAY = new Day("THURSDAY");
static final Day FRIDAY = new Day("FRIDAY");
static final Day SATURDAY = new Day("SATURDAY");
static final Day SUNDAY = new Day("SUNDAY");
private String name;
private Day(String name) {
this.name = name;
}
}
위와 같이 각 열거형 상수는 객체의 주소값을 갖게 된다.
- 따라서 상수끼리의 == 연산이 가능하다. (객체의 주소를 비교하게 됨)
- 그러나 < , > 연산은 불가능하다. (참조 타입을 <,> 연산할 수 없음)
모든 열거형의 조상, Enum 클래스
Enum 클래스를 알아보자. Enum 클래스는 다음과 같은 추상 클래스이다.
public abstract class Enum<E extends Enum<E>>
implements Constable, 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 hashCode() {
return super.hashCode();
}
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;
}
public static <T extends Enum<T>> T valueOf(Class<T> enumClass, String name) {
T result = enumClass.enumConstantDirectory().get(name);
if (result != null)
return result;
if (name == null)
throw new NullPointerException("Name is null");
throw new IllegalArgumentException(
"No enum constant " + enumClass.getCanonicalName() + "." + name);
}
// ... 계속
}
Java에서 모든 열거형들은 암묵적으로 `java.lang.Enum`클래스를 상속받는다.
그러니까 실은! 컴파일러로 인해 생성되는 클래스는 아래와 더 유사하다.
public final class Day extends java.lang.Enum<Day> {
public static final Day MONDAY = new Day("MONDAY", 0);
public static final Day TUESDAY = new Day("TUESDAY", 1);
public static final Day WEDNESDAY = new Day("WEDNESDAY", 2);
public static final Day THURSDAY = new Day("THURSDAY", 3);
public static final Day FRIDAY = new Day("FRIDAY", 4);
public static final Day SATURDAY = new Day("SATURDAY", 5);
public static final Day SUNDAY = new Day("SUNDAY", 6);
private static final Day[] ENUM_VALUES = {MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY};
private Day(String name, int ordinal) {
super(name, ordinal);
}
// 계속 ...
}
Enum 클래스를 상속받으므로 Enum 클래스에 내장된 함수들을 이용할 수 있다.
대표적인 몇 가지를 알아보자면 다음과 같다.
- name() : 열거형 상수의 이름을 반환한다.
- ordinal() : 열거형 상수의 순서(0부터 시작)를 반환한다.
- values() : 열거형의 모든 상수를 배열로 반환한다.
- valueOf(String name) : 이름에 해당하는 열거형 상수를 반환한다.
(궁금 🧐) 내가 직접 Enum 클래스를 상속 받아 클래스를 구성할 수 있을까? O / X
정답은 X이다. 개발자는 Enum 클래스를 직접 상속하여 구현할 수 없다.
다음과 같이 클래스를 직접 생성하려고 하면, 에러가 발생하여 컴파일을 할 수가 없다.
cannot directly extend 'java.lang.Enum' !!!
즉 Enum 클래스는 일반적인 추상 클래스처럼 사용자가 직접 상속하여 구현할 수 없도록 막아두었으며, 열거형 선언시 오직 컴파일러로 인해 열거형 클래스의 생성이 처리된다.
Enum의 사용
각 열거형 상수에 0부터 시작하여서 id처럼 값이 붙는다고 했다. 그리고 이를 ordinal() 메서드로 가져올 수 있다.
그렇지만 열거형 상수에 다른 값을 넣고 싶다면? 이를테면 숫자가 아닌 String 값을 저장하고 싶다면 어떻게 할까?
원하는 값 저장하기
위에서 알아봤듯이 열거형은 실은 특수한 클래스이므로 각 상수에 저장하고 싶은 값을 멤버로 추가해줄 수가 있다.
이를 위해선 아래 두 가지 작업이 필요하다.
- 지정된 값을 저장할 인스턴스 변수를 선언한다.
- 열거형 생성 시 해당 변수를 초기화할 수 있는 생성자를 추가한다.
즉 각 열거형 상수는 같은 클래스 객체이므로, 클래스 필드와 생성자를 정의해주고 매개변수로 필드 값을 넣어줌으로써 상수 객체로서 사용하는 것이다.
예를 들어서 열거형 Day에 한글 이름을 추가해주고 싶다면 아래와 같이 수정한다.
public enum Day {
MONDAY("월요일"), TUESDAY("화요일"), WEDNESDAY("수요일"), THURSDAY("목요일"), FRIDAY("금요일"), SATURDAY("토요일"), SUNDAY("일요일");
private final String KOREAN_NAME;
Day(String koreanName) {
this.KOREAN_NAME = koreanName;
}
public String getKoreanName() {
return this.KOREAN_NAME;
}
}
- 각 상수 옆에 괄호( )를 달고 한글 이름을 추가해줬다. ( 괄호 안에 들어가는 데이터가 클래스로 변환 시 생성자 안에 들어가게 된다.)
- 그리고 이 때 어떤 상수 옆에는 이름을 추가하고, 어떤 상수 옆에는 이름을 추가하지 않을 수 없다. (흠 개발자가 직접 추가한 생성자가 무조건 객체 생성자로 사용되는 듯 하다..)
- 인스턴스 변수 KOREAN_NAME를 정의해줬다.
- KOREAN_NAME을 초기화할 수 있는 생성자를 추가해줬다.
- 한글 이름을 가져올 수 있는 메서드는 따로 없으므로 직접 구현해줬다.
이제 다음과 같이 한글 이름을 가져올 수 있다.
System.out.println(Day.MONDAY.getKoreanName()); // "월요일"
원하는 메서드 저장하기
클래스 필드와 생성자를 정의해주고 매개변수로 필드 값을 넣어줌으로써 원하는 데이터를 추가할 수 있었다.
필드를 추가하여 각 상수마다 다른 값을 추가해줬다면, 메서드를 추가하여 각 상수마다 다른 작업을 수행하도록 할수도 있을까?
있다 ! 이는 추상 메서드를 추가함으로써 가능하다.
- 추상 메서드를 포함하는 클래스는 추상 클래스가 되며, 하위 클래스에서 추상 메서드를 반드시 구현하여야만 인스턴스를 생성할 수 있다.
- 따라서 각 열거형 상수를 위해 인스턴스를 생성하려면 추상 메서드를 반드시 구현하여야 한다.
- 각 열거형 상수에 익명 클래스의 형태로 추상 메서드의 동작을 정의한다.
public enum Day {
MONDAY("월요일") {
public void printEnergy() {
System.out.println("50%");
}
}, TUESDAY("화요일") {
public void printEnergy() {
System.out.println("40%");
}
}, WEDNESDAY("수요일") {
public void printEnergy() {
System.out.println("30%");
}
}, THURSDAY("목요일") {
public void printEnergy() {
System.out.println("20%");
}
}, FRIDAY("금요일") {
public void printEnergy() {
System.out.println("70%");
}
}, SATURDAY("토요일") {
public void printEnergy() {
System.out.println("90%");
}
}, SUNDAY("일요일") {
public void printEnergy() {
System.out.println("80%");
}
};
private final String KOREAN_NAME;
Day(String koreanName) {
this.KOREAN_NAME = koreanName;
}
public String getKoreanName() {
return this.KOREAN_NAME;
}
public abstract void printEnergy();
}
이제 다음과 같이 사용할 수 있다.
Day.MONDAY.printEnergy(); // 50%
계산기 과제의 도전 기능 구현에서 Enum을 잘 활용하고 싶어서 Enum에 대해 복습을 해보았다!
졸업 프로젝트를 하면서도 Java의 Enum을 잘 써먹었던 기억이 있다.
현업에서 어떻게 사용이 될 수 있을지에 대해서는 아래 아티클을 참고하면 좋을 것 같다.
https://techblog.woowahan.com/2527/
그럼 이만 끝
'프로그래밍 언어 > Java' 카테고리의 다른 글
추상클래스 vs 인터페이스, 언제 어떤 것을 사용할까? (0) | 2025.01.07 |
---|---|
Java의 예외처리 (함수 너 회피형이야?) (1) | 2025.01.02 |
잠깐 ! JVM 정리하고 갑시다 (1) | 2024.12.31 |
[Java] 문자열(String) 내장 함수 정리 (1) | 2024.01.11 |
[Java] CharSequence란? (0) | 2024.01.11 |