Annotation(이하 어노테이션)
은 코드의 특정 구문이 무엇이고 어떻게 처리할지를 컴파일러 등에게 알리는 역할을 수행합니다. 어노테이션은 @메세지
의 형태로 전달됩니다.
정확하게는 다음과 같은 세 가지 목적을 위해 사용됩니다.
- 컴파일 타임에서 사용되는 정보 전달
- 빌드 도구가 코드를 자동 생성할 때 사용되는 정보 전달
- 런타임에서 특정 기능을 처리하고자 할 때 사용되는 정보 전달
대표적으로 메소드 오버라이딩에서 사용했던 @Override
가 현재로써는 가장 익숙한 어노테이션이라고 할 수 있죠.
이러한 어노테이션은 세 종류가 있습니다. 자바에서 기본적으로 제공하는 표준 어노테이션
, 어노테이션 정의에 사용되는 메타 어노테이션
, 사용자가 직접 정의하는 사용자 정의 어노테이션
이 있습니다.
컴파일러에게 해당 메소드가 오버라이딩되었다고 알립니다.
해당 메소드 등을 더 이상 사용하지 않음을 알립니다. 만약 @Deprecated
가 붙은 메소드를 사용하게 되면 오류가 발생합니다.
해당 인터페이스가 함수형 인터페이스임을 알립니다. 함수형 인터페이스는 Java 8부터 지원하는 문법입니다.
어노테이션이 선언된 위치에서 발생하는 컴파일 경고를 무시합니다.
Java 7 이상부터 사용가능한 어노테이션으로, 제네릭 등의 가변 인자의 매개변수를 사용할 때 발생하는 경고를 표시하지 않습니다.
어노테이션이 적용되는 대상을 지정합니다.
지정 대상은 ElementType
열거 상수를 통해 지정하는데, 이에 대해서는 잠시후 더 자세히 알아보도록 하겠습니다.
어노테이션 정보를 javadoc 문서에 포함시킵니다.
어노테이션이 영향을 주는 시점을 결정합니다.
마찬가지로 RetentionPolicy
라는 열거 상수를 통해 지정하는데 이 역시도 잠시후에 살펴보겠습니다.
어노테이션이 하위 클래스에 상속될 지를 결정합니다.
어노테이션이 반복되어서 적용될 지를 결정합니다.
자바에서 제공하고있는 어노테이션들을 알아봤으니 이번에는 직접 어노테이션을 만드는 사용자 정의 어노테이션
을 만들어보겠습니다.
어노테이션의 정의는 인터페이스의 정의와 유사합니다.
//정의
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
어노테이션을 사용하면 정의된 어노테이션이 적용될 범위를 지정할 수 있습니다. 범위에 대한 정보는 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("어노테이션이 적용되지 않았습니다.");
}
}
}