처음 Enum 에 대해 배울 때 단순히 여러 상수를 정의할 때 사용하였다.
상수를 그냥 쓰다보면 예상치 못한 오류가 생길 수 있으므로 따로 열거형으로 정의해서 사용한다. JAVA 에서는 Enum 안에 함수도 들어가는 거 같고 생각보다 복잡한 느낌이 있어서 이번 기회에 재대로 정리해본다.
아래의 예시를 보자.
class Korea {
static final int SEOUL = 0;
static final int DAEGU = 1;
static final int BUSAN = 2;
}
class America {
static final int LA = 0;
static final int NEWYORK = 1;
}
public class Main{
private static void main(String[] args) {
System.out.println(Korea.SEOUL == America.LA ? "TRUE" : "FALSE" );
}
}
출력결과는 TRUE이다. 0 == 0 과 같은 코드이므로 참이다. 하지만 의미적으로 생각했을 때 SEOUL 과 LA는 같은가??
그리고 America 의 상수값들이 변경된다면 또 결과가 달라진다.
class Korea {
static final int SEOUL = 0;
static final int DAEGU = 1;
static final int BUSAN = 2;
}
class America {
static final int LA = 100;
static final int NEWYORK = 101;
}
public class Main{
private static void main(String[] args) {
System.out.println(Korea.SEOUL == America.LA ? "TRUE" : "FALSE" );
}
}
우리는 LA , SEOUL 등 똑같이 사용하고 싶은데 상수의 값이 변해버리면 다시 코딩해야 되는 불상사가 발생한다.
그래서 Enum을 사용한다.
Enum을 사용해서 코드를 수정하면 아래처럼 된다.
enum Korea { SEOUL , DAEGU , BUSAN }
enum America { LA , NEWYORK }
public class Main{
private static void main(String[] args) {
// compile 에러 !
System.out.println(Korea.SEOUL == America.LA ? "TRUE" : "FALSE" );
}
}
이처럼 Type에 대해 검사를 하기 때문에 보다 안정적인 코딩이 가능하다.
그리고 Korea.SEOUL 은 내부적으로 0이라는 id 값을 가지고 있다. DAEGU는 1 , BUSAN 은 2를 가진다. America 의 LA는 0 , NEWYORK 는 1 을 가지고 있다. 이러한 값을 ordinal() 이라는 함수를 통해 볼 수 있다. 하지만 ordinal 값을 사용하는 것은 타입의 안정성에 문제가 있으므로 지양하는 바이다.
- Enum 의 내부 동작원리 ( 자바의 정석 참조 )
enum의 내부 동작 모습을 더 알아보기 위해 MyEnum 을 정의하였다.
실제 enum 에 compareTo를 구현이 되었있기 때문에 Comparable<MyEnum> 을 implements 하였다.
아래 코드를 보고 설명하겠다.
id 는 MyEnum 객체들끼리 공유하는 변수이므로 static으로 선언해야 새로 생성되는 ordinal값을 id를 이용해 초기화 할 수 있다. 즉, 새로 MyEnum 객체가 생성될때 마다 중복되지 않는 고유의 ordinal값을 가질 수 있게 된다. name은 "SEOUL" 과 같은 String 값으로 생성자를 통해 초기화 할 수 있도록 하였다.
MyEnum 객체를 제네릭스를 이용해 수정하면 아래와 같다.
<T extends MyEnum<T>> 라고 한 이유는 compareTo 메소드의 매개변수로 t 를 받는 데, t.ordinal() 에서 ordinal() 함수가 있다는 것을 알려주기 위함이다. MyEnum<T> 을 포함한 자손들이 매개변수로 들어올것을 확정짓는 다면 t.ordinal() 은 컴파일 에러를 낼 이유가 없다.
이제 MyEnum을 완성하였다. MyEnum을 사용하는 예시를 소개한다.
뒤에서 enum으로 바꾼 코드와 비교해볼 것이므로 바로 와닿지 않더라도 넘어가길 권장한다.
MyTransportation2 라고 2를 붙인 이유는 MyTransportation1 은 enum을 사용한 구현으로 뒤에서 보여줄 것이다.
먼저 MyTransportation2 는 추상클래스이다. 인스턴스를 생성할 수 없는 클래스를 의미한다.
하지만 추상클래스의 추상메서드를 익명 클래스로 확장(extends) 하여 구현(implements)하는 순간 더 이상 추상클래스가 아니며 인스턴스화 할수 있다. 그래서 다음과 같은 코드가 가능한 것이다.
static final Transportation2 Bus = new Transportation2("BUS",100) {
@Override
int fare(int dist) {
return dist * BASIC_FARE;
}
};
더 자세한 설명이 필요하다면 스택오버플로우의 링크를 참조하자.
stackoverflow.com/questions/16785922/creating-the-instance-of-abstract-class-or-anonymous-class
다시 본론으로 와서 Transportation2 는 Bus 와 Train 에 대해 기본요금이 다르고 거리에 따라 fare를 계산할 수 있는 기능이 있다.
메인함수에서 사용은 다음과 같다.
System.out.println("bus 기본요금은 : "+Transportation2.Bus.getBASIC_FARE() + " 이며 20km 이동하면 : " + Transportation1.Bus.fare(20));
System.out.println("Train 기본요금은 : "+Transportation2.Train.getBASIC_FARE() + " 이며 20km 이동하면 : " + Transportation1.Train.fare(20));
정리하면, enum은 따로 열거형이라는 것이 존재한다기 보다는 자바코드가 맞다고 본다.
이제 enum으로 구현하여 더 간결하게 작성해본다.
익명 클래스로 추상클래스를 확장 및 구현하여 만든 Bus 와 enum에서 정의한 Bus를 비교해보기 바란다.
'Java' 카테고리의 다른 글
[JAVA] ArrayList remove for loop ( ConcurrentModificationException) (0) | 2021.02.24 |
---|---|
[JAVA] Comparator 란? (feat. Generics ) (0) | 2021.02.24 |
[JAVA] Comparable 이란? (0) | 2021.02.19 |
[JAVA] next_permutation, prev_permutation (0) | 2020.09.19 |
백트래킹을 이용한 순열 in java (0) | 2020.08.30 |
댓글