오늘의하루

[Java] Enum (열거형), Annotation (애너테이션) 본문

JAVA

[Java] Enum (열거형), Annotation (애너테이션)

오늘의하루_master 2022. 8. 31. 14:04

Enum은 관련된 상수들을 같이 묶어 놓은 것을 의미합니다.

Enum

// Enum 사용 x

class Card{
// 무늬
    static final int CLOVER = 0;
    static final int HEART = 1;
    static final int DIAMOND = 2;
    static final int SPADE = 3;
       
// 숫자
    static final int TWO = 0;
    static final int THREE = 1;
    static final int FOUR = 2;
       
    final int kind;
    final int num;
}

이 경우에 if(Card.CLOVER == Card.TWO)를 하면 true가 나오지만 이것은 의미적으로 맞지 않습니다.

  • CLOVER은 무늬이고 TWO는 숫자인데 이걸 비교해서 true가 나오는 건 이상하다.
// Enum 사용 O

class Card{
    enum Kind {CLOVER, HEART, DIAMOND, SPADE} // 열거형 Kind를 정의
    // 자동으로   0      1       2       3  값이 부여된다.
    enum Value{TWO, THREE, FOUR} // 열거형 value를 정의
    // 자동으로 0     1      2 값이 부여된다.
    final Kind kind; // 타입이 int가 아니라 Kind
    final Value value;
}

Enum을 사용한 후 if(Card.Kind.CLOVER == Card.Value.TWO)를 하면 타입이 다르기 때문에 컴파일 에러가 발생한다.

Enum을 정의하는 방법

enum 열거형 이름 {상수명 1, 상수명 2...}

  • 자동으로 상수명 1 = 0, 상수명 2 = 1... 값이 부여된다.

Enum 타입의 변수를 선언하고 사용하는 방법

enum Direction {EAST, SOUTH, WEST, NORTH}

class Unit{
    int x, y;
    Direction dir;
    
    void init(){
        dir = Direction.EAST;
    }
}

열거형 상수의 비교는 ==와 compareTo()로 가능하다.

if(dir == Direction.EAST){
    x++;
}else if (dir > Direction.WEST){ // Error! 열거형 상수에 비교연산자 사용 불가
    // ...
}else if(dir.compareTo(Direction.WEST) > 0){
    // dir은 Direction.EAST (0)이고 Direction.WEST (2) 이므로 결과는 음수
    // ...
}

열거형 상수를 비교할 때 비교 연산자를 사용하지 못하는 이유는 위에 있는 dir의 타입은 Direction(객체)이기 때문이다.

  • 주의! Direction.EAST를 출력하면 0이 나오는 게 아니라 EAST가 출력된다.

[복습] compareTo()

A.compareTo(B);

  • 가장 쉽게 생각하는 방법은 "A - B"를 해보는 것이다.
  • 만약 A와 B가 같다면 0이 나오게 된다.
  • A가 크다면 양수가 나오게 된다.
  • B가 크다면 음수가 나오게 된다.

열거형의 조상(java.lang.Enum)

모든 열거형은 Enum의 자식이며 아래에 있는 메서드를 상속받는다.

구분 특징
class<E> getDeclaringClass() 열거형의 class 객체를 반환한다.
String name() 열거형 상수의 명칭을 문자열로 반환한다.
int ordinal() 열거형 상수의 정의된 순서를 반환( 0부터 시작 )
T valueOf(class<T> enumType, String name) 지정된 열거형에서 name과 일치하는 열거형 상수를 반환

이 외에도 values(), valueOf()는 컴파일러에 의해 자동으로 추가된다.

  • static E [] values()
  • static E valueOf(String name)
    • 예시 Direction d = Direction.valueOf("WEST"); 
      • == Direction.WEST;

예제로 알아보기

enum Direction {EAST, SOUTH, WEST, NORTH}

// 아래 세가지는 모두 같은 의미이지만 각기 다른 방법으로 작성해보았다.
Direction d1 = Direction.EAST;
Direction d2 = Direction.valueOf("WEST");
// == Direction.WEST;
Direction d3 = Enum.valueOf(Direction.class, "EAST");
// == Direction.EAST;
// ==================================================================

System.out.println("d1 = " + d1); // EAST
System.out.println("d2 = " + d2); // WEST
System.out.println("d1 = " + d3); // EAST

System.out.println("d1 == d2 ?" + (d1 == d2)); // false
System.out.println("d1 == d3 ?" + (d1 == d3)); // true
System.out.println("d1.equals(d3) ?" + d1.equals(d3)); // true
System.out.println("d1.compareTo(d2) ?" + (d1.compareTo(d2)); // -2
System.out.println("d1.compareTo(d3) ?" + (d1.compareTo(d3)); // 0
// System.out.println("d1 > d2 ?" + (d1 > d2)); >> Error! 객체끼리의 비교연산은 불가능

Direction[] dArr = Direction.values(); // Direction에 있는 상수명을 모두 저장
for(Direction d : dArr){
    System.out.printf("%s = %d\n", d.name(), d.ordinal()); // 이름과 인덱스
}
// 결과
// EAST = 0
// SOUTH = 1
// WEST = 2
// NORTH = 3

열거형에 멤버 추가하기

불연속적인 열거형 상수의 경우 원하는 값을 괄호() 안에 적는다.

  • enum Direction {EAST(1), SOUTH(5), WEST(-1), NORTH(10)}

괄호()를 사용하려면 인스턴스 변수와 생성자를 새로 추가해줘야 한다.

enum Direction{
    EAST(1), SOUTH(5), WEST(-1), NORTH(10);
    
    private final int value; // 정수를 저장할 인스턴스 변수 추가
    
    Direction(int value){
        this.value = value;
    }
    public int getValue(){return value;}
}
  • 열거형의 생성자는 묵시적으로 private이므로 외부에서 객체 생성이 불가능하다.

예제로 알아보기

enum Direction{
    EAST(1,">"), SOUTH(5,"V"), WEST(-1,"<"), NORTH(10,"^");
    
    private static final Direction[] DIR_ARR = Direction.values();
    private final int value;
    private final String symbol;
    
    Direction(int value, String symbol){
         this.value = value;
         this.symbol = symbol;
    }
    
    public int getValue(){return value;}
    public String getSymbol(){return symbol;}
    
    public static Direction of(int dir){
        if(dir < 1 || dir > 4){
            throw new IllegalArgumentException("Invalid value : " + dir);
        }
        return DIR_ARR[dir-1];
    }
    
    public Direction rotate(int num){
        num = num % 4;
        if(num < 0){
            num = num + 4; // 음수일때 시계 반대 반향으로 회전
        }
        return DIR_ARR[(value -1 + num) % 4];
    }
    
    public String toString(){
        return name() + " " + getSymbol();
    }
}

for(Direction d : Direction.values()){
    System.out.printf("%s = %d [index = %d]\n", d.name(), d.getValue(), d.ordinal());
}
// 결과
// EAST = 1 [index = 0]
// SOUTH = 5 [index = 1]
// WEST = -1 [index = 2]
// NORTH = 10 [index = 3]

Direction d1 = Direction.EAST;
Direction d2 = Direction.of(1); // == Direction.EAST

System.out.printf("d1 = %s, %d\n",d1.name(), d1.getValue());
System.out.printf("d2 = %s, %d\n",d2.name(), d2.getValue());
System.out.println(Direction.EAST.rotate(1)); // SOUTH V
System.out.println(Direction.EAST.rotate(2)); // WEST <
System.out.println(Direction.EAST.rotate(-1)); // NORTH ^
System.out.println(Direction.EAST.rotate(-2)); // WEST <

Annotation (애너테이션)

주석처럼 프로그래밍 언어에 영향을 미치지 않으면서 유용한 정보를 제공하는 역할을 한다.

  • 소스코드와 관련 문서의 불일치를 막아주는 역할을 한다.
  • 소스코드 안에 " /** 내용 */ "으로 주석을 달면 된다.
  • javadoc.exe라는 프로그램이 위에서 작성한 애너테이션을 추출해서 따로 문서를 만든다.

표준 애너테이션

java에서 제공하는 애너테이션

  • @Override : 오버 라이딩하는 메서드라는 것을 컴파일러에게 알린다.
  • @Deprecated : 앞으로 사용하지 않을 것을 권장하는 대상에 붙인다.
  • @SuppressWarnings : 컴파일러의 특정 경고 메시지가 나타나지 않게 해 준다.
  • @SafeVarargs : 제네릭스 타입의 가변 인자에 사용한다.(JDK 1.7)
  • @FuntionalInterface : 함수형 인터페이스라는 것을 알린다. (JDK 1.8)
  • @Native : native 메서드에서 참조되는 상수 앞에 붙인다. (JDK 1.8)
  • @Target* : 애너테이션이 적용 가능한 대상을 지정하는 데 사용한다.
  • 메타 애너터이션 - 애너테이션을 만들 때 사용한다.
    • @Documented : 애너테이션 정보가 javaboc으로 작성된 문서에 포함되게 한다.
    • @Inherited : 애너테이션의 자식 클래스에 상속되도록 한다.
    • @Retention : 애너테이션이 유지되는 범위를 지정하는 데 사용한다.
    • @Repeatable : 이너테이션을 반복해서 적용할 수 있게 한다. (JDK 1.8)
Comments