도서/자바의 신

[도서/자바의 신] #17 어노테이션이라는 것도 알아야 한다

yulee_to 2022. 12. 25. 06:18

자바의 신

✔️이 글은 [자바의 신 - 이상민 지음] 도서를 바탕으로 정리한 글입니다. 


어노테이션이란?

어노테이션(Annotation)은 클래스나 메소드, 변수 등의 선언시에 @를 사용하는 것으로

  • 컴파일러에게 정보를 알려주거나
  • 컴파일할 때와 설치(deployment)시의 작업을 지정하거나
  • 실행할 때 별도의 처리가 필요할 때 

사용한다.

프로그램에 영향이 있는 어노테이션도 있고 없는 것도 있다.

미리 정해져 있는 어노테이션들은 딱 3개뿐

사용하기 위해 정해진 어노테이션은 3개가 있다.

  • @Override : 해당 메소드가 부모 클래스에 있는 메소드를 Override했다는 것을 명시적으로 선언해줌
  • @Deprecated : 클래스나 메소드가 더이상 사용되지 않는 경우에 써줌. deprecated된 메소드를 써도 경고만 주고 컴파일은 제대로 됨
  • @SupressWarnings : 경고가 나오는 코드에 써줘서 일부러 이렇게 코딩한거니 경고를 띄울 필요 없다고 알려줌. 소괄호를 써서 속성값을 지정해줄 수도 있음 ex) all, deprecation...

어노테이션을 선언하기 위한 메타 어노테이션

어노테이션을 선언하기 위한 메타 어노테이션 4개가 있다.

  • @Target : 어노테이션을 어떤 것에 적용할지 선언할 때 사용. 소괄호 안에 적용 대상을 써줌
  • @Retention : 얼마나 오래 어노테이션 정보가 유지되는지를 선언할때 사용. 소괄호 안에 적용 대상을 써줌
  • @Documented : 해당 어노테이션에 대한 정보가 Javadocs(API) 문서에 포함된다는 것을 선언
  • @Inherited : 모든 자식 클래스에서 부모 클래스의 어노테이션을 사용 가능하는 것을 선언

@Target의 적용 대상

요소 타입 대상
CONSTRUCTOR 생성자 선언시
FIELD enum 상수를 포함한 필드 값 선언시
LOCAL_VARIABLE 지역 변수 선언시
METHOD 메소드 선언시
PACKAGE 패키지 선언시
PARAMETER 매개 변수 선언시
TYPE 클래스, 인터페이스, enum 등 선언시

소괄호 안에 중괄호로 묶고 콤마로 구분해 여러개의 대상을 지정해줄 수 있다.

 

@Retention 적용 대상

  대상
SOURCE 어노테이션 정보가 컴파일시 사라짐
CLASS 클래스 파일에 있는 어노테이션 정보가 컴파일러에 의해서 참조 가능함.하지만, 가상머신에서는 사라짐
RUNTIME 실행시 어노테이션 정보가 가상 머신에 의해 참조 가능

어노테이션을 선언해보자

1. @Target으로 어노테이션 사용 대상을 지정

2. @Retention으로 유지 정보를 지정

3. 어노테이션 이름 앞에는 @interface를 해주면 이후에 @어노테이션이름으로 어노테이션 사용이 가능해짐

4. 어노테이션 선언 안에 메소드를 구현해주면 이 어노테이션을 사용할 때 해당 항목에 대한 타입으로 값을 지정 가능

5. 어노테이션 안 메소드에 default가 붙으면 default 뒤에 있는 값이 이 어노테이션을 사용할 떄의 기본값이 됨

 

어노테이션 관련 클래스들은 java.lang.annotation 패키지에 선언되어 있다.

 

예제

package annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface UserAnnotation {
    public int number();
    public String text() default "this is first annotation";
}
package annotation;

public class UserAnnotationSample {
    @UserAnnotation(number=0)
    public static void main (String args[]) {
        UserAnnotationSample sample = new UserAnnotationSample();
    }
    @UserAnnotation(number=1)
    public void annotationSample1() {}
    @UserAnnotation(number=2, text="second")
    public void annotationSample2(){}
    @UserAnnotation(number=3, text="third")
    public void annotationSample3() {}
}

어노테이션에 선언한 값은 어떻게 확인하지?

package annotation;

import java.lang.reflect.Method;

public class UserAnnotationCheck {
    public static void main (String args[]) {
        UserAnnotationCheck sample = new UserAnnotationCheck();
        sample.checkAnnotations(UserAnnotationSample.class);
    }
    public void checkAnnotations(Class userClass){
        Method[] methods = userClass.getDeclaredMethods();
        for(Method tempMethod : methods) {
            UserAnnotation annotation = tempMethod.getAnnotation(UserAnnotation.class);
            if( annotation != null) {
                int number = annotation.number();
                String text = annotation.text();
                System.out.println(tempMethod.getName() + "() : number=" +number + " text=" +text);
            }else {
                System.out.println(tempMethod.getName() + "() : annotation is null");
            }
        }
    }
}

Class와 Method 클래스는 자바의 리플렉션(Reflection)이라는 API에서 제공하는 클래스들이다. 

Class는 클래스의 정보를 확인하고, Method는 메소드의 정보를 확인하는 데 사용한다.

Class의 getDeclaredMethods()는 해당 클래스에 선언되어 있는 메소드들의 목록을 배열로 리턴해준다.

Method의 getAnnotation()이라는 메소드는 해당 메소드에 선언되어 있는 매개 변수로 넘겨준 어노테이션이 있는지 확인하고 있으면 그 어노테이션 객체를 리턴해준다.

annotation에 선언된 메소드를 호출하면 그 값을 리턴해준다.

어노테이션도 상속이 안돼요

어노테이션을 선언할 때 미리 만들어 놓은 어노테이션을 확장할 수 없다.

 

어노테이션의 용도

  • 제약사항 등을 선언하기 위해 : @Deprecated, @Override, @NotNull
  • 용도를 나타내기 위해 : @Entity, @TestCase, @WebService
  • 행위를 나타내기 위해 : @Statefull, @Transaction
  • 처리를 나타내기 위해 : @Column, @XmlElement

예전엔 자바 애플리케이션의 설정을 XML이나 properties라는 파일에 지정해왔는데 그렇게 하면 설정이 복잡해지고, 어떤 설정이 어디에 쓰이는지 이해하려면 많은 시간이 소요되었다. 어노테이션이 만들어지고 나서 각 설정이 필요한 위치에 관련 설정이 존재하면서 코드에 대한 가독성이 좋아졌다. 하지만 아직도 XML과 같은 설정파일이 필요한 부분이 존재하기 때문에 남아있다.

 

롬복(lombok)이라는 건 개발자가 필요한 작업을 어노테이션 선언만으로도 편하게 처리할 수 있도록 도와주는 것이다.

롬복 사용시 관련된 라이브러리가 필요한데 사용법은 홈페이지를 참고해라.(https://projectlombok.org/)

ex)@Getter는 변수를 단순히 리턴하는 메소드를 자동 생성, @Setter는 변수의 값을 바꾸는 메소드를 자동 생성해준다.


정리해 봅시다

1. @Override 어노테이션의 용도는?

해당 메소드가 부모 클래스에 있는 메소드를 Overriding한다는 것을 명시적으로 선언한다.

2. @SupressWarnings 어노테이션의 용도는?

경고를 제외해준다.

3. @Deprecated 어노테이션의 용도는?

더이상 사용되지 않음을 명시한다.

4. 어노테이션을 선언할 때 사용하는 어노테이션은?

메타어노테이션

5. 4번의 답에 있는 어노테이션들을 사용할 때 import해야 하는 패키지는?

java.lang.annotation

6. @Target 어노테이션의 용도는?

어노테이션을 어떤 것에 적용할지를 지정해준다.

7. @Retention 어노테이션의 용도는?

어노테이션 유지 정보를 지정하는 데 사용한다. 

8. @Inherited 어노테이션의 용도는?

자식 클래스가 부모 클래스의 어노테이션을 사용 가능하다는 것을 선언한다. 

9. 어노테이션을 선언할 때 class 대신 어떤 예약어를 사용하나요?

@interface

728x90