Java Annotation - 놓치기 쉬운 개념들

이강현·2025년 4월 18일

놓치기 쉬운 개념들

목록 보기
14/19

Annotation 의 역사와 현재

자바를 개발하면서 소스코드에 대한 문서를 따로 만들기보다 소스코드와 문서를 하나의 파일에서 관리하는 방법을 선택했습니다.
소스코드의 주석/** ... */에 정보를 저장하고, 그 주석으로부터 HTML 문서를 생성해내는 javadoc 을 사용했습니다.
주석에 포함된 @가 붙은 태그들을 javadoc 이 읽어서 문서를 작성하는데사용했습니다.
이러한 기능을 응용한 것이 Annotation 입니다.
Annotation 은 주석처럼 코드에는 영향이 없으면서, javadoc 처럼 다른 프로그램에게 정보를 제공하는 기능을 합니다.

Standard Annotation

자바에서 기본적으로 제공하는 annotation입니다.
주로 컴파일러에게 정보를 제공하는 역할을 합니다.

Standard Annotation설명
@Override컴파일러에게 오버라이딩 메서드라는 것을 알림
@Deprecated대상은 앞으로 사용하지 않는 것을 권장 함
@SuppressWarnings컴파일러의 특정 경고 메시지를 발생하지 않도록 함
@SafeVarargs제네릭 타입의 가변인자에 사용
@FunctionalInterface함수형 인터페이스라는 것을 알림
@Nativenative 메서드에서 참조되는 상수에 사용
  • @Override 를 사용하면 오버라이딩 할 때 발생할 수 있는 오타 등의 문제를 방지할 수 있습니다. 조상 클래스에 같은 시그니처의 메서드가 없으면 컴파일러 에러가 발생합니다.

  • java 는 backward compativility 를 매우 중요하게 생각합니다. 따라서 @Deprecated 가 붙은 소스코드를 여러 곳에서 확인할 수 있는데, 사용하지 않는 것이 좋습니다. 사용하게 되면 컴파일러 경고 메시지가 출력됩니다.

  • @FunctionalInterface 를 사용하면 함수형 인터페이스를 올바르게 선언했는지 확인할 수 있습니다. 단 하나의 추상메서드를 가진 인터페이스가 아닌 경우 컴파일러 에러가 발생합니다.

  • @SuppressWarnings 를 사용하면 컴파일러 경고 메시지억제합니다. 단순히 보기 싫은 경고 메시지를 위해 사용하는 것이 아닌, 경고에 대한 인지조치를 취한 뒤 사용해서, 새로운 문제가 발생 했을 때 알 수 있도록 활용하는 것이 좋습니다.

Meta Annotation

Meta annotation 은 다른 annotation정의할 때 사용하는 annotation 입니다.

Meta Annotation설명
@Target이 애너테이션이 적용될 수 있는 대상을 지정
@Document애너테이션 정보가 javadoc 문서에 포함되도록 함
@Inherited애너테이션이 자손 클래스로 상속되도록 함
@Retention애너테이션이 유지되는 범위를 지정
@Repeatable애너테이션을 반복해서 적용할 수 있도록 함
  • @Target 으로 적용대상을 지정해주지 않으면 기본적으로 모든 대상에 적용 가능합니다.

Define

  • 애너테이션을 정의할 때는 인터페이스와 유사하게 정의하면 됩니다.
  • 상수는 정의할 수 있지만, default 메서드는 정의할 수 없습니다.
  • 반환값이 있고 매개변수가 없는 추상메서드 형태의 맴버들을 element(요소) 라고 합니다.
  • 요소의 default 값을 정해줄 수 있습니다.

Marker Annotation

  • 요소가 없는 annotation 을 marker annotaion 이라고 합니다.
  • @Override 는 marker annotation 입니다.
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.SOURCE)
public @interface Override {
} 
import java.lang.annotation.Annotation;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

public class AnnotationTest {
    public static void main(String[] args) {
        ParentClass parent = new ParentClass();

        @SuppressWarnings({"unchecked"})
        Class<ParentClass> parentClass = (Class<ParentClass>) parent.getClass();
        Annotation[] annotations = parentClass.getAnnotations();
        MyAnnotation myAnnotation = (MyAnnotation) annotations[0];
        System.out.println(myAnnotation.count());

        ChildClass child = new ChildClass();
        Class<ChildClass> childClass = (Class<ChildClass>) child.getClass(); // unchecked warning
        MyAnnotation annotation = childClass.getAnnotation(MyAnnotation.class);
        System.out.println(annotation.testBy());
    }
}

@MyAnnotation(testType = TestType.FIRST, testDate = @DateTime(yymmdd = "250101", hhmmss = "246060"))
@ValueAnnotation({3, 4, 5})
class ParentClass {
    @DateTime(yymmdd = "123456", hhmmss = "123456")
    public int i = 10;
}

class ChildClass extends ParentClass {}

@Retention(RetentionPolicy.RUNTIME)
@Inherited
@interface MyAnnotation {
    int MAX = 999;

    int count() default 0;
    String testBy() default "user";
    String[] testTools() default {};
    TestType testType();
    DateTime testDate();
}

enum TestType { FIRST, FINAL }

@Retention(RetentionPolicy.RUNTIME)
@interface DateTime {
    String yymmdd();
    String hhmmss();
}

@interface ValueAnnotation {
    int[] value() default { 1, 2 };
}
profile
백엔드 개발자 지망생입니다.

0개의 댓글