[Java] @Retention 어노테이션 까보기(RetentionPolicy / Source, Class, Runtime)

안녕하세요. 오늘은 커스텀 어노테이션을 생성할 때 주로 사용하는 어노테이션인 @Retention어노테이션에 대해서 다루어보겠습니다.

 

보통 어노테이션은 다음과 같이 선언됩니다.

 

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface MyAnnotation {
}

@Retention 어노테이션으로 어느 시점까지 어노테이션의 메모리를 가져갈 지 설정하고, @Target 어노테이션으로 필드, 메소드, 클래스, 파라미터 등 선언할 수 있는 타입을 설정하면 대부분 커스텀 어노테이션은 쉽게 생성할 수 있습니다. 여기서 속성부분만 설정해주면요!!

 

그럼이제 @Retention 어노테이션을 까보겠습니다!!!

 

/**
 * Indicates how long annotations with the annotated type are to
 * be retained.  If no Retention annotation is present on
 * an annotation type declaration, the retention policy defaults to
 * {@code RetentionPolicy.CLASS}.
 *
 * <p>A Retention meta-annotation has effect only if the
 * meta-annotated type is used directly for annotation.  It has no
 * effect if the meta-annotated type is used as a member type in
 * another annotation type.
 *
 * @author  Joshua Bloch
 * @since 1.5
 * @jls 9.6.3.2 @Retention
 */
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Retention {
    /**
     * Returns the retention policy.
     * @return the retention policy
     */
    RetentionPolicy value();
}

역시 어노테이션답게 @Retention 어노테이션에도 자기자신이 쓰이네요ㅎㅎ. @Target도 마찬가지입니다.

 

맨 첫줄부터 정의가 되어있습니다. 어노테이션 타입을 어디까지 보유할지를 설정하는 것이라고 하네요. 

 

디폴트값은 Class 입니다. 근데 RetentionPolicy는 무엇일까요??

 

RetentionPolicy의 값을 넘겨주는 것으로 어노테이션의 메모리 보유 범위가 결정됩니다.

 

RetentionPolicy는 enum 클래스로 다음과 같이 선언되어있습니다.

 

RetentionPolicy

/**
 * Annotation retention policy.  The constants of this enumerated type
 * describe the various policies for retaining annotations.  They are used
 * in conjunction with the {@link Retention} meta-annotation type to specify
 * how long annotations are to be retained.
 *
 * @author  Joshua Bloch
 * @since 1.5
 */
public enum RetentionPolicy {
    /**
     * Annotations are to be discarded by the compiler.
     */
    SOURCE,

    /**
     * Annotations are to be recorded in the class file by the compiler
     * but need not be retained by the VM at run time.  This is the default
     * behavior.
     */
    CLASS,

    /**
     * Annotations are to be recorded in the class file by the compiler and
     * retained by the VM at run time, so they may be read reflectively.
     *
     * @see java.lang.reflect.AnnotatedElement
     */
    RUNTIME
}

- SOURCE : 어노테이션을 사실상 주석처럼 사용하는 것. 컴파일러가 컴파일할때 해당 어노테이션의 메모리를 버립니다. 

- CLASS : 컴파일러가 컴파일에서는 어노테이션의 메모리를 가져가지만 실질적으로 런타임시에는 사라지게 됩니다. 런타임시에 사라진다는 것은 리플렉션으로 선언된 어노테이션 데이터를 가져올 수 없게 됩니다. 디폴트값입니다.

- RUNTIME : 어노테이션을 런타임시에까지 사용할 수 있습니다. JVM이 자바 바이트코드가 담긴 class 파일에서 런타임환경을 구성하고 런타임을 종료할 때까지 메모리는 살아있습니다.

 


위에 선언한 @MyAnnotation을 이용하여 Retention을 변경해보면서 컴파일된 클래스파일을 살펴보겠습니다.

먼저 어노테이션을 사용할 클래스를 생성하고 메소드위에 어노테이션을 사용합니다.

public class MyClass {

    @MyAnnotation
    void method() {

    }

}
@Retention(RetentionPolicy.RUNTIME)

Runtime 이기 때문에 Class 파일에는 붙어있습니다. 당연한 결과입니다.

@Retention(RetentionPolicy.CLASS)

마찬가지로 CLASS 단계이기 때문에 .class 파일에는 존재하게 됩니다. 그렇다면 과연 차이점은 무엇일까요???

직접 .class 파일을 열어 바이트코드를 확인해보겠습니다.

 

RetentionPolicy.RUNTIME

RetentionPolicy.CLASS

바이트 코드로 작성된 부분중에 RuntimeVisibleAnnotation, RuntimeInVisibleAnnotation으로 구분지어 놓은 것을 확인할 수 있습니다. 

 

즉, CLASS는 어노테이션을 단지 바이트코드에서 확인할 수 있는 수준으로만 정의해놓을 뿐 Runtime 환경에서는 역시나 버려지는 메모리인 것입니다.

@Retention(RetentionPolicy.SOURCE)

SOURCE는 .class 파일에서도 보이지 않습니다. 단지 개발자의 어떤 용도로만 사용되다가 컴파일할 때 버려지는 소스이기 때문입니다.

 

댓글

Designed by JB FACTORY