2025. 4. 17. 21:25ㆍBack-End/JAVA
자바에서 enum은 흔히 "고정된 상수 집합"을 만들 때 사용한다.
예를 들어 사용자 역할을 나타내기 위해 이렇게 쓴다:
public enum Role {
ADMIN,
USER,
GUEST
}
이렇게 사용하면 Role.ADMIN, Role.USER처럼 코드가 명확해지고, 값도 제한할 수 있다.
그래서 enum은 값이 고정된 목록을 안전하게 관리하는 수단으로 많이 쓰인다.
그런데 여기서 한 발 더 나아가면, enum은 단순한 상수를 넘어서
객체이자 싱글톤으로도 활용할 수 있는 구조라는 걸 알게 된다.
enum은 객체다
예를 들어, 아래처럼 enum에 생성자와 필드를 추가할 수 있다.
public enum LogLevel {
DEBUG("디버그"),
INFO("정보"),
ERROR("에러");
private final String description;
LogLevel(String description) {
this.description = description;
}
public String getDescription() {
return description;
}
}
이렇게 하면 LogLevel.DEBUG.getDescription()처럼 동작하는데,
이는 DEBUG가 단순 문자열이 아니라 객체처럼 동작하는 enum 상수라는 뜻이다.
즉, enum 상수는 JVM이 생성한 고정된 인스턴스(객체)다.
enum은 싱글톤이다
자바에서 싱글톤(Singleton)은 "클래스의 인스턴스를 단 하나만 생성하는 패턴"이다.
전통적으로는 다음처럼 구현한다:
public class Settings {
private static final Settings INSTANCE = new Settings();
private Settings() {}
public static Settings getInstance() {
return INSTANCE;
}
}
하지만 이렇게 하면 리플렉션, 직렬화/역직렬화 상황에서
싱글톤이 깨지는 경우가 생길 수 있다.
enum으로 싱글톤 구현하기
public enum SettingsManager {
INSTANCE;
private boolean darkModeEnabled = false;
public void enableDarkMode() {
darkModeEnabled = true;
}
public boolean isDarkModeEnabled() {
return darkModeEnabled;
}
}
사용법도 단순하다:
SettingsManager.INSTANCE.enableDarkMode();
boolean dark = SettingsManager.INSTANCE.isDarkModeEnabled();
- 생성자 없이
- null 체크도 없이
- 객체 한 개만 보장되고
- 쓰레드 안전하게 동작한다
enum 싱글톤의 장점
| 1. 객체가 오직 하나만 생성됨 | enum은 JVM이 로딩할 때 상수를 단 한 번만 생성해줌 |
| 2. 쓰레드 안전(Thread-safe) | 별도 synchronized 없이도 멀티쓰레드 환경에서 안전 |
| 3. 리플렉션 공격에도 강함 | 일반 클래스는 리플렉션으로 생성자를 열 수 있지만, enum은 차단됨 |
| 4. 직렬화/역직렬화에도 안전 | 일반 클래스는 deserialize 시 객체가 새로 만들어질 수 있지만, enum은 동일 객체 유지 |
| 5. 코드가 간결하고 직관적 | INSTANCE.method()만으로 사용 가능, 관리 편함 |
언제 enum 싱글톤을 쓰면 좋을까?
- 전역적으로 관리해야 하는 설정, 상태 관리자
- 일정한 환경에서 한 번만 초기화되어야 하는 객체
- 서비스 전체에서 공통으로 쓰이는 유틸 클래스
예: 설정 매니저, 토큰 매니저, 로그 필터, 글로벌 캐시 핸들러 등
처음엔 enum을 단순히 "상수 묶음"이라고만 생각했지만, 사실 enum은 JVM이 보장하는 고정 객체,
더 나아가 가장 안전한 싱글톤 구현 수단이라는 걸 알게 됐다.
클래스를 만들고, static 필드를 만들고, 동기화 신경 쓸 필요 없이 그저 enum ClassName { INSTANCE; ... }만으로 끝이다.
'Back-End > JAVA' 카테고리의 다른 글
| @RequiredArgsConstructor와 @Builder와의 차이 (0) | 2025.04.22 |
|---|---|
| final 필드와 @RequiredArgsConstructor는 왜 같이 쓰는가? (0) | 2025.04.22 |
| Runnable이란? 비동기 워커 설계에서 마주친 첫 스레드 인터페이스 (0) | 2025.03.23 |
| 메서드 참조 :: (0) | 2024.11.22 |
| Stream() (0) | 2024.11.22 |