Enum
자바에서는 final로 자료형을 상수(constant)로 만들 수 있지만, 어떤 집합이 모두 상수로만 이뤄져있다면 그 집합은 굳이 class로 선언할 필요가 없습니다
이때, enum으로 선언하면 이 객체는 상수의 집합 이라는것을 명시화할 수 있습니다
Enum의 특징
1. 객체를 상수처럼 사용할수있다
public enum Game {
//상수객체
LOSE(-10,"hong"), //클래스 로드 시점에 생성 고정
Win(20,"kang");
private final int score;
private String MVP;
public int getScore(){
return score;
}
Game(int score,String MVP){ //암묵적으로 private
this.score=score;
this.MVP = MVP;
}
}
클래스나 인터페이스의 상수(final)선언이 클래스가 로드 되는 시점에 생성되는 것처럼, Enum 또한 클래스가 로드되는 시점에 생성됩니다
위 코드를 보면 생성자가 보이지만 Enum의 생성자는 default 가 private
이기 때문에 외부에서 임이로 생성할 수 없기 때문에 클래스가 로드되는 시점에 생성이 고정 된다는 특징이 있습니다
생성자를 public으로 바꾸려고 시도하면 컴파일 에러가 발생한다.
Game result = Game.WIN;
따라서 외부에선 이렇게 내부에서 선언해둔 상수만 사용할 수 있습니다
열거형에 정의된 상수 하나하나가 열거형의 객체임을 의미합니다
2. 유일하게 하나의 인스턴스를 공유하여 사용한다(싱글톤)
LOSE(-10,"hong"),
Win(20,"kang");
위와 같이 생성된 상수들은 클래스 로드 시점에 생성되어 싱글톤 형태로 어플리케이션 전체에서 공유됩니다
따라서 Enum에 변수나 변경 메서드를 사용하는것은 Multi Thread환경에서 문제가 생길 수 있습니다
public enum Game {
LOSE(-10,"hong"),
Win(20,"kang");
private final int score;
private String MVP;
public int point //고정되지 않는 변수
public void givePoint(){ //변경 메서드
this.point++;
}
Game(int score,String MVP){
this.score=score;
this.MVP = MVP;
}
}
이와 같은 코드를 사용한다면 인스턴스 LOSE 나 Win 은 싱글톤임으로 point 변수를 공유합니다
이때, point 변경을 LOSE가 하게되면 Win의 point도 변경되는 문제점이 있다는 뜻임으로 멀티 스레드 환경에서는 각별한 주의가 필요합니다
3. 클래스와 같은 문법 체계를 따른다.
예시 코드에서 보듯이 상수 인스턴스를 제외하면 클래스와 문법체계가 동일합니다
4.상속이 불가하다.
Enum은 내부적으로 java.lang.enum을 상속받고있습니다. java는 다중상속을 허용하지 않기 때문에 Enum은 다른 클래스를 상속받을수 없습니다
인터페이스 구현은 가능합니다.
5. java.lang.enum
java.lang.enum를 내부적으로 상속받기 때문에 다른 클래스를 상속받을순 없지만, java.lang.enum 클래스가 제공하는 다양한 내부 API를 사용할 수 있습니다
1. values()
- Enum 클래스가 가지고 있는 모든 상수 값을 배열의 형태로 리턴 한다.
- 참고로 단순히
String
의 형태로 단순 반환하는 것이 아니라 인스턴스를 반환하는 것이다. 즉 Enum 클래스가 가지고 있는 모든 인스턴스를 배열에 담아 반환하는 것이다.
@Test
public void testValues(){
Game[] arr = Game.values(); //모든 인스턴스를 배열에 담아 반환
for(Game r:arr){
System.out.println(r.getScore());
}
}
//-10 20
2. valueOf()
- 파라미터로 받은 String과 비교하여 일치하는 상수 인스턴스를 반환한다.
@Test
public void testValueOf(){
System.out.println(Game.valueOf("Win").getScore());
}
//20
3.ordinal()
- 해당 인스턴스의 인덱스를 반환한다.
@Test
public void testOrdinal(){
Game[] arr = Game.values();
for(Game r:arr){
System.out.println(r.ordinal());
}
}
//0 1
4.열거형에 추상메서드 사용하기
Game 열거형은 다양한 맴버를 유지하고있고 열거형 상수들은 이를 공유하여 사용하지만 열거형 상수마다 메서드를 다르게 만들어 쓰고싶을 수 있습니다
public enum Game {
WIN(10,"홍길동"){
@Override
public void handle(){
//do something
}
},
LOSE(20,"강감찬"){
@Override
public void handle(){
//do something
}
};
public abstract void handle(); //추상메서드 추가!
private final int score;
private String MVP;
public int point
public void givePoint(){
this.point++;
}
Game(int score,String MVP){
this.score=score;
this.MVP = MVP;
}
}
이렇게 하면, 열거형 상수들은 해당 추상 메서드를 반드시 재정의 해야합니다, 이를 통해, 열거형 상수마다 추상메서드를 다르게 재정의해서 사용할 수 있습니다
Enum의 장점
위 Enum의 특징만으론 굳이 Enum을 쓸필요가 있는지 와닿지가 않습니다, 구체적으로 어떠한 장점이 있는지 알아보고 활용을 고민해볼 필요가 있겠습니다
0. 인스턴스를 상수처럼 사용할수있다.
클래스 로드 시점에 인스턴스를 싱글톤으로 생성하여 상수처럼 사용할수있다.
생성자가 private임으로 외부 생성이 불가능
1.상태 데이터를 한 곳에서 관리할 수 있다.
public enum Game {
LOSE(-10, "hong"), //패배 state
Win(20, "kang"); //승리 state
private final int score;
private String MVP;
Game(int score, String MVP) {
this.score = score;
this.MVP = MVP;
}
}
위 예시처럼 승리와 패배의 형태 데이터를 한곳에서 관리할수있다.
2. 상태와 행위를 한곳에서 관리할수있다.
public enum Game {
//상태
LOSE(-10, "hong"),
Win(20, "kang");
private final int score;
private String MVP;
Game(int score, String MVP) {
this.score = score;
this.MVP = MVP;
}
//행위 로직
public void getResult() {
System.out.println(score);
System.out.println(MVP);
}
}
Enum은 여러 상태데이터를 관리하는것과 더불어 완전한 클래스의 형태이기 때문에 상태 데이터을 활용한 행위로직을 설계하고 관리할수있다.
상태와 연관있는 행위 또한 한 곳에서 관리 할 수 있는 장점
3. Enum의 Comparable
Enum은 내부적으로 Comparable을 구현하고 있으며, 상수의 선언 순서로 정렬이 유지됩니다
4. 람다를 이용하여 Enum사용 극대화
추후 람다 파트에서 다루도록 하겠습니다
기타
- IDE의 적극적인 지원
- 자동완성, 오타검증, 텍스트 리팩토링 등등
- 허용하고자 하는 값으로 제한하기
- 리팩토링시 변경 범위가 최소화
- 상수를 Enum에서 관리하기 때문에 내용의 추가가 필요하더라도, Enum 코드외에 수정할 필요가 없습니다.
- [중요]다른 언어와 달리 Java 에서는 Enum 이 완전한 기능을 가지고 있는 클래스라서 상수와 관련된 작업들을 추가 할 수 있다.
Reference
https://velog.io/@kyle/%EC%9E%90%EB%B0%94-Enum-%EA%B8%B0%EB%B3%B8-%EB%B0%8F-%ED%99%9C%EC%9A%A9
'개발자 준비 > JAVA' 카테고리의 다른 글
[JAVA 더 깊게] JAVA One Paper (0) | 2022.01.10 |
---|---|
서버간 통신의 시작 RestTemplate (0) | 2022.01.04 |
Optional(for null-safe) (0) | 2021.12.31 |
JVM, JRE, JDK (0) | 2021.12.18 |
Record (0) | 2021.11.23 |