enumeration

자바 공부를 하면서 참고한 서적입니다. _자바 이펙티브 2__

명품자바에센셜(생능출판사, 황기태), 이것이 자바다(한빛미디어, 신용권), 디자인패턴과 리팩토링

Enumerated Type

Enum은 열거 자료형이라고 합니다. 자바 1.5부터 도입이 되었고 완전한 기능을 갖춘 클래스입니다.

Enum은 이미 선언된 Enum 상수 외의 객체는 사용할 수 없으며, toString 메서드를 호출하면 인쇄
가능 문자열로 쉽게 변환 할 수 있습니다.

즉, Enum은 선언되면 변경 불가능 입니다. (immutable)

Enum은 int로 선언한 상수와 성능면에서 비슷하나, 자료형을 메모리에 올리고 초기화 하는 공간적
/시간적 비용때문에 약간 손해를 보긴 합니다.

int 상수

하지만 Enum을 사용하면 코드 가독성이 높아지고, 안전하고 강력합니다.

Enum 내부에는 선언된 상수를 순서대로 저장하는 배열을 반환하는 static values 메서드가 기본으로
정의 되어 있습니다.


  • Enum은 언제 사용 해야 할까?

고정된 상수집합이 필요할 때 사용

ex) 요일(월화수목금토일), 계절(봄여름가을겨울), 태양계 행성 등

인스턴스 생성과 상속을 방지

Enum은 DB 에 넣지 않아도 될 것들 (절대 바뀌지 않을 상수), ENUM 사용 시 만약 상수 하나가 바뀌거나 삭제되면 서버를 다시 올렸다 내려야함. 우리끼리 내부에서 사용하는 거면 상관없지만, 외부에서 사용하는 거면, 서버 올렸다 내리는것도 허락을 받아야하기 때문에, 절대 바뀌지 않을 상수값을 만들어야 할 때만 사용해야 합니다.

  • Enum은 어떻게 사용할까?

먼저 Enum 이름을 정해야합니다(첫글자는 대문자)

public enum enumName { ….. }

그리고 열거 타입 이름으로 소스파일(.java)을 생성 합니다.

그리고 Enum 클래스 안에 작성된 상수들은 대문자로 작성 되어 있어야 합니다.

열거형은 main 메소드 내부에 선언하면 안됩니다.

Enum내부에 생성자, 인터페이스, 추상메소드도 정의가 가능합니다.

또한, 각 열거형에 속성을 지정할 수도 있습니다.

열거형으로 선언한 상수들은 public static final 형태로 제공 됩니다.

열거형은 자기 이름으로 객체에 바로 접근 할 수 있습니다.

public Enum Week{} 일경우 Week.객체명


  • Enum에서 제공하는 메소드

메소드(Method)

리턴타입 메소드 특징
String name() 열거객체의 문자열을 리턴
int ordinal() 전체 열거객체중 몇번 째인지 알려준다.
int compareTo() 열거객체를 비교
열거 타입 valueOf(String name) 매개변수에 주어진 문자열의 열거 객체를 리턴
열거 배열 values() 열거객체들을 배열로 리턴

Enum을 선언할때 안에 열거된 상수들은 맨 앞에 열거된 상수는 정수 값0을 가지고 뒤로갈수록 1씩 증가합니다.

  public enum Position {
  부장, 차장, 과장, 대리, 사원
  // 내부적으로 인덱스를 가지는데 선언한 순서대로 0, 1, 2, 3, 4를 가진다
  // 뒤에 나열된 값이 더 크다고 판단된다.
  }

따라서 compareTo()로 비교할때 부장.compareTo(차장)은 차장이 더 크다고 판단합니다.
따라서 equals()메소드로 비교를하여 정렬할때 주의 하여야 합니다.

  • Enum 상수 사용법

    enumName.상수

    Position.부장, Position.과장 ….. 방법으로 사용

Enum 사용 예제


  • 올바르지 못한 Enum(열거형) 선언
  class DayTest {
    public static void main(String[] args){
      enum Day { MON, TUE, WED, TUR, FRI, SAT, SUN }; // ERROR
    }
  }
  • 열거형 사용 예제 1
  enum Season {
    WINTER,
    SPRING,
    SUMMER,
    FALL

    Season time;
    time = Season.SPRING;
    // 만약에 선언된 상수를 제외한 값이 들어갈 경우
    // Type Mismatch Error가 발생합니다.
  }
  • 열거형 사용 예제 2
  public enum Status {
    ON(1), OFF(0); // 열거형의 각 객체들이 각각의 객체변수를 가지게 합니다.
    private int statusNum;

    // Constructor
    Status(int i){
      statusNum = i;
    }

    // Method
    public int getStatus() {
      return statusNum;
    }
  }

  class Radio {
    Status = status;
  }

  Class DayTest {
    public static void main(String[] args) {
      Radio a = new Radio();
      a.status = Status.ON;
      System.out.println(a.status);
      System.out.println(a.status.getStatus());
    }
  }

  // 출력 결과
  ON
  1
  public enum Nation {
    KOREA("100,210KM"),
    AMERICA("1,857,000KM"),
    CHINA("9,597,000KM");

    private String area;

    // Constructor
    private Nation(String area) {
      this.area = area;
    }
    public String getArea() {
      return area;
    }
  }

위 코드를 보면 열거상수안에 속성값이 존재할 경우 보통 속성값을 나타낼 변수
생성자, 값을 반환할 메소드가 필요합니다.

생성자를 private로 지정 해서 객체 생성을 방지하고, 클래스 외부에서 사용을 방지합니다.
따라서 하위 클래스도 생성 못합니다.

Enum은 생성자 타입을 public이나 protected로 지정할 수 없습니다.

즉, 생성자가 private이므로 new를 통한 객체 생성이 불가능 합니다.

Enum(열거형)은 열거형이름.객체명으로 접근 가능하다고 했는데 아래와 같이 생각하면
이해가 조금 더 빨리 되실 겁니다.

Enum Constant(열거형 상수)Static Method(정적 메소드)라 생각하고
Enum이라는 단어를 Class로 생각하면 클래스명.메소드처럼 사용이 가능하므로
열거이름.객체명으로 접근이 가능합니다.

Static Member

if(a.compareTo(b) > 0) { System.out.println(“b가 사전상 앞에 있음”) }

else { System.out.println(“a가 사전상 앞에 있음”)}

A.compareTo(B)는 B를 기준으로 A의 상대적 위치 사전상 한칸 차이 -1 음수

B.compareTo(A)는 A를 기준으로 B의 상대적 위치 사전상 한칸 차이 +1 양수

ENUM 상수에 속성 추가

ENUM에서 속성을 여러개 줄 경우, 그 속성에 대한 이름으로 필드를 생성하고, 생성자도 생성해서 사용해야 한다.
그 이유는 다음과 같습니다.

public enum DisPlayState {
  YES("Y","출력"),
  NO("N","미출력"),
  NOT_FOUND("","");

  private String code;
  private String name;

  DisPlayState(String code, String name) {
      this.code = code;
      this.name = name;
  }

  public static List<DisPlayState> findAll() {
      List<DisPlayState> disPlayStates = new ArrayList<>();
      for (DisPlayState disPlayState : DisPlayState.values()) {
          if(disPlayState != DisPlayState.NOT_FOUND) {
              disPlayStates.add(disPlayState);
          }
      }
      return disPlayStates;
  }
}

Enum 클래스에서 Enum 상수안에 속성을 집어넣는 행위는, 객체를 초기화하는 행위랑 같다. 즉, Enum 클래스 안에는 객체 생성 및 초기화와, 필드, 생성자를 다 가지고 있습니다.

  // YES("Y","출력") 코드를 변환하면 아래와 같습니다.
  YES("Y","출력")
  DisPlayState YES = new DisPlayState("Y", "출력");