[Java] Annotation

Bam·2024년 3월 12일
0

Java

목록 보기
60/98
post-thumbnail

Annotation

Annotation(이하 어노테이션)은 코드의 특정 구문이 무엇이고 어떻게 처리할지를 컴파일러 등에게 알리는 역할을 수행합니다. 어노테이션은 @메세지의 형태로 전달됩니다.

정확하게는 다음과 같은 세 가지 목적을 위해 사용됩니다.

  • 컴파일 타임에서 사용되는 정보 전달
  • 빌드 도구가 코드를 자동 생성할 때 사용되는 정보 전달
  • 런타임에서 특정 기능을 처리하고자 할 때 사용되는 정보 전달

대표적으로 메소드 오버라이딩에서 사용했던 @Override가 현재로써는 가장 익숙한 어노테이션이라고 할 수 있죠.

이러한 어노테이션은 세 종류가 있습니다. 자바에서 기본적으로 제공하는 표준 어노테이션, 어노테이션 정의에 사용되는 메타 어노테이션, 사용자가 직접 정의하는 사용자 정의 어노테이션이 있습니다.

표준 어노테이션

@Override

컴파일러에게 해당 메소드가 오버라이딩되었다고 알립니다.

@Deprecated

해당 메소드 등을 더 이상 사용하지 않음을 알립니다. 만약 @Deprecated가 붙은 메소드를 사용하게 되면 오류가 발생합니다.

@FuntcionalInterface

해당 인터페이스가 함수형 인터페이스임을 알립니다. 함수형 인터페이스는 Java 8부터 지원하는 문법입니다.

@SuppressWarnings

어노테이션이 선언된 위치에서 발생하는 컴파일 경고를 무시합니다.

@SafeVarargs

Java 7 이상부터 사용가능한 어노테이션으로, 제네릭 등의 가변 인자의 매개변수를 사용할 때 발생하는 경고를 표시하지 않습니다.

메타 어노테이션

@Target

어노테이션이 적용되는 대상을 지정합니다.
지정 대상은 ElementType 열거 상수를 통해 지정하는데, 이에 대해서는 잠시후 더 자세히 알아보도록 하겠습니다.

@Documented

어노테이션 정보를 javadoc 문서에 포함시킵니다.

@Retention

어노테이션이 영향을 주는 시점을 결정합니다.
마찬가지로 RetentionPolicy라는 열거 상수를 통해 지정하는데 이 역시도 잠시후에 살펴보겠습니다.

@Inherited

어노테이션이 하위 클래스에 상속될 지를 결정합니다.

@Repeatable

어노테이션이 반복되어서 적용될 지를 결정합니다.


사용자 정의 어노테이션

자바에서 제공하고있는 어노테이션들을 알아봤으니 이번에는 직접 어노테이션을 만드는 사용자 정의 어노테이션을 만들어보겠습니다.

어노테이션 정의

어노테이션의 정의는 인터페이스의 정의와 유사합니다.

//정의
public @interface 어노테이션이름 {}

//사용할 때
@어노테이션이름

어노테이션은 속성을 가질 수 있습니다. 마치 필드를 선언하듯이 타입과 이름을 적는데, 이때 반드시 이름 뒤에 괄호를 붙여주어야합니다. default 키워드를 사용하면 속성에 기본값을 넣을 수 있습니다.

다음 예시는 속성이 있는 어노테이션을 만들고 사용하는 예시입니다.

public @interface 어노테이션이름 {
	타입 속성명();	//속성 선언
    타입 속성명() default;	//기본값이 있는 속성
}

//사용할 때
@어노테이션이름(속성 =);

//속성이 여러개라면
@어노테이션이름(속성1 =, 속성2 =);

기본 속성으로 기본값이 없는 필수 속성인 value()를 사용할 수도 있습니다. value는 어노테이션을 사용할 때 따로 속성이름을 표시하지 않아도 됩니다.

public @interface 어노테이션이름 {
	String value();
}

//사용할 때
@어노테이션이름("값");

이때 다른 속성과 value가 함께 사용된다면, value를 반드시 표기해주어야합니다.

public @interface 어노테이션이름 {
	String value();
    int num();
}

//사용할 때
@어노테이션이름(value = "값", num = 10);

어노테이션 적용 범위 지정 @Target

@Target 어노테이션을 사용하면 정의된 어노테이션이 적용될 범위를 지정할 수 있습니다. 범위에 대한 정보는 ElementType 열거 상수로 정의되어있습니다.

ElementType적용 범위
TYPE클래스, 인터페이스, 열거형
ANNOTATION_TYPE어노테이션
FIELD필드
CONSTRUCTOR생성자
METHOD메소드
LOCAL_VARIABLE지역 변수
PACKAGE패키지
@Target({ ElementType.TYPE, ElementType.ANNOTATION_TYPE })
public @interface 어노테이션이름 {}

위와 같이 정의된 어노테이션은 클래스, 인터페이스, 열거형, 어노테이션에만 사용할 수 있게 됩니다.

어노테이션 영향 범위

@Retention을 사용하면 어노테이션이 언제 시작되어서 언제 종료될 것인지를 결정할 수 있습니다. 영향 범위도 마찬가지로 RetentionPolicy 열거 상수에 정의되어 있습니다.

RetentionPolicy적용 시작 시점적용 종료 시점
SOURCE컴파일 과정컴파일 후
CLASS메모리 로딩메모리 로딩 후
RUNTIME실행중계속 유지

예제 코드

그럼 위에서 알아본 어노테이션에 대한 정보를 토대로 사용자 정의 어노테이션을 만들어보겠습니다.

먼저 어노테이션 선언입니다.

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

어노테이션을 적용시킨 메소드를 가진 클래스입니다.

public class Obj {
    @MyAnnotation("어노테이션 호출")
    public void myMethod() {
        System.out.println("사용자 정의 어노테이션 만들고 사용하기");
    }
}

어노테이션이 적용되었는지 확인을 하고 어노테이션의 value()도 출력하는 main입니다. 지난 포스트에서 배운 리플렉션을 이용해 어노테이션 정보를 취득하고 이용합니다.

public class Main {
    public static void main(String[] args) {
        Method[] methods = Obj.class.getDeclaredMethods();	//Obj 클래스의 메소드들 취득

		//해당 메소드에 어노테이션이 적용되었는지 if문으로 검사
        if (methods[0].isAnnotationPresent(MyAnnotation.class)) {
        	//어노테이션이 있다면 어노테이션 정보 취득
            MyAnnotation ma = methods[0].getAnnotation(MyAnnotation.class);

            System.out.println("어노테이션이 적용되었습니다.");
            System.out.println("어노테이션 value: " + ma.value());	//어노테이션 value() 출력
        }
        else {
            System.out.println("어노테이션이 적용되지 않았습니다.");
        }
    }
}

0개의 댓글