ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [Java] Enum (열거형), Annotation (애너테이션)
    JAVA 2022. 8. 31. 14:04
    728x90
    반응형

    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)
    728x90
    반응형
Designed by Tistory.