관리 메뉴

제뉴어리의 모든것

[Section1][Java] 심화 - Enum 본문

코드스테이츠/정리 블로깅

[Section1][Java] 심화 - Enum

제뉴어리맨 2022. 7. 18. 11:30

열거형이란

서로 관련된 상수들을 묶어서 편리하게 사용하기 위한 문법.

 

열거형의 특징

  • 코드의 간략화
  • 타입 안정성 보장 (JAVA 열거형의 특징, 실제 value값이 같아도 enum 타입 (enum 클래스명)이 다르면 같지 않음)
  • 상수명의 중복을 피할 수 있다 (같은 Spring이여도 계절 분류의 Spring과 프레임웍 분류에서의 Spring은 다르다)
  • enum 클래스 안에 상수들은 사실 하나하나 해당 enum클래스의 객체이다.
enum Season {
	Spring, //Season 의 객체이다
    SUMMER, //Season 의 객체이다
    FALL,   //Season 의 객체이다
    WINTER  //Season 의 객체이다
}
  • 기본타입만 사용 가능하던 switch 문에서 사용 가능 (case문에 enum타입은 적으면 안됨. 즉, 상수 변수명만)

 

 

 

열거형의 주의사항

  • 한 상수에대하여 따로 값을 지정하지 않으면 0부터 1씩 증가되어 할당된다.
  • 열거형 상수간의 "==" 사용이 가능하다. (equals의 비해 빠른 성능), 그러나 ">" 와 같은 비교 연산자는 사용불가.
  • 상수간 비교시에는 compareTo를 사용해야함 (서로 같으면 0, 왼쪽이 크면 양수, 오른쪽이 크면 음수)
  •  

 

열거형의 기본 메소드

모든 열거형의 조상인 java.lang.Enum의 메소드들이 존재하다

 

리턴 타입메소드(매개변수)설명

String name() 열거 객체가 가지고 있는 문자열을 리턴하며, 리턴되는 문자열은 열거타입을 정의할 때 사용한 상수 이름과 동일합니다.
int ordinal() 열거 객체의 순번(0부터 시작)을 리턴합니다.
int compareTo(비교값) 주어진 매개값과 비교해서 순번 차이를 리턴합니다.
열거 타입 valueOf(String name) 주어진 문자열의 열거 객체를 리턴합니다.
열거 배열 values() 모든 열거 객체들을 배열로 리턴합니다.

 

열거형에 멤버 추가하기

열거형에 멤버를 추가한다는것은 enum 클래스내에 멤버(변수)를 추가한다는것도 되지만, 정의된 상수들 또한 멤버를 갖고 생성자로 초기화를 해야한다는것이다. 왜냐하면 위에 열거형 특징 중 네번째에서 말했듯이, 각 상수들은 사실 enum타입의 객체들이기 때문이다.

 

  • 코드
package jeongseok.practice;

enum User{

    GOLD(10,"골드"), SILVER(5,"실버"), BRONZE(3,"브론즈"), GUEST(0,"손님"); //끝에 ;들어감

    private final int code;      //위에 괄호안에 있는 10, 5, 3, 0 이 할당될 변수
    private final String krGrade; //위에 괄호안에 있는 골드, 실버, 브론즈, 손님 이 할당될 변수

    User(int code, String krGrade) { //생성자, 암묵적으로 private이다. (외부에서 생성자를 호출할 수 없다)
        this.code = code;
        this.krGrade = krGrade;
    }

    public int getCode(){
        return this.code;
    } //getter
    public String getKrGrade() {
        return krGrade;
    } //getter

}

public class EnumPractice {
    public static void main(String[] args) {

        User user1 = User.GOLD;
        User user2 = User.GUEST;

        if(user1.getCode() > user2.getCode())
        {
            System.out.println("user1이 더 높은 회원입니다");
        }
    }
}

생성자는 private 밖에 허용하지 않는다. 그러므로 외부에서 new로 해당 enum 클래스를 생성할 수 없다.

각 멤버들은 private이 강제는 아니지만 캡슐화의 특징을 살려 private을 지정해주었고, getter를 정의해 주었다.

그리고 각 멤버변수들은 final로 설정해주었다. 이것또한 강제는 아니지만 enum이 상수집합이라는 특성을 살려 final로 설정해주었고 setter를 정의하지 않았다.

그러나 멤버변수를 final 지정하지 않고 setter를 만들 수도 있다.

결론은, 각 상수에 멤버변수를 추가하려면 enum클래스 내부에 멤버 변수 정의와 그에 맞게 생성자에 매개변수도 추가하여야 하고 각 상수의 괄호안에 값들을 지정해줘야한다.

 

열거형에 추상 메소드 추가하기

enum 클래스내에 추상메소드를 선언하고, 각 상수들마다 해당 추상 메소드를 구현하도록 만들 수 있다.

 

  • 코드
package jeongseok.practice;

enum Transportation{

    BUS(1000)  //BUS 상수
            {         // calcuCost 추상 메소드 재정의  
        @Override
        int calcuCost(int distance) {
            return distance * basicCost; }},
    
    TAXI(2000) //TAXI 상수
            {       // calcuCost 추상 메소드 재정의  
        @Override
        int calcuCost(int distance) {
            return distance * basicCost;
        }},
    
    AIRPLANE(40000) //AIRPLANE 상수
            {       // calcuCost 추상 메소드 재정의  
        @Override
        int calcuCost(int distance) {
            return (distance * basicCost) * 2;
        }};

    protected final int basicCost; //protected로 해야 각 상수에서 접근 가능

    Transportation(int basicCost) {
        this.basicCost = basicCost;
    }

    abstract int calcuCost(int basicCost); //추상 메소드 선언
}

public class EnumPractice2 {
    public static void main(String[] args) {
        Transportation transportation = Transportation.AIRPLANE;
        System.out.println(transportation.calcuCost(2)); // 재정의된 calcuCost 호출
    }
}

각 상수들 뒤에 {} 를 붙여서 선언된 추상 메소드를 재정의 해주어야 한다.

그리고 그 재정의 과정에서 각 상수들마다 메소드의 내용을 달리해서 정의도 가능하다 (AIRPLANE 상수의 재정의 부분을 보면 (distance * basicCost) 를 *2 하고 있다)

그리고 추상 메소드 내에서 쓰이는 변수는 protected를 선언해주어야 가 상수들이 접근할 수 있다. ( protected final int basicCost; )

 

 

열거형의 이해

위에서 말했다시피, 열거형 상수 하나하나가 사실은 속해있는 enum타입의 객체이다.

아래가 우리가 배운 enum의 선언 방법이다.

enum User{ GUEST, NORMAL, SILVER, GOLD}

 

위에 enum이 선언된 내용을 번역하자면 아래와 같다.

class User{
	User final User GUEST = new User("GUEST");
	User final User GUEST = new User("NORMAL");
	User final User GUEST = new User("SILVER");
	User final User GUEST = new User("GOLD");
}

그러므로 아래 소스에서 user == findUser 로 비교하여 true가 나올 수 있는것이다.

각 상수는 객체이고, 이미 만들어져 있는 객체들의 주소값은 변하지 않는다.

user 변수와 findUser 변수 모두 User enum클래스 안에서 생성된 객체를 참조 (본인변수가 특정 객체의 주소값을 가지고 있음으로써 가리키고 있는 상태) 하기 때문이다.

 

 

 

  • 참고 소스
package enu;



enum User{
    GUEST, NORMAL, SILVER, GOLD
}

public class EnumPracticeSwitch {

    public static void main(String[] args) {

        User[] userGrade = User.values(); // User enum타입에 존재하는 모든 상수들을 배열로

        User user = userGrade[1];
        User user2 = userGrade[3];
        User findUser = User.valueOf("NORMAL"); // 특정 상수 변수명으로 enum변수를 찾음.

        System.out.println("findUser = " + findUser);
        System.out.println("user == findUser : " + (user == findUser));
        System.out.println("user.compareTo(user2) : " + user.compareTo(user2)); //user2의 값 - user2 -> -2

        switch (user) {

            case GOLD:
                System.out.println("value = "+ user.ordinal() + ", 골드입니다");
                break;
            case SILVER:
                System.out.println("value = "+ user.ordinal() + ", 실버입니다");
                break;
            case NORMAL:
                System.out.println("value = "+ user.ordinal() + ", 노멀입니다");
                break;
            case GUEST:
                System.out.println("value = "+ user.ordinal() + ", 게스트입니다");
                break;
        }
    }
}