Annotation이란?
Annotation은 자바 5부터 도입된 메타데이터 기반의 기능으로, 클래스, 메서드, 필드 등 프로그램 요소에 설명 정보를 부여하는 데 사용됩니다. 이는 코드의 실행 로직과 무관하며, 컴파일 타임 또는 런타임 시 특정 프레임워크나 도구가 이를 해석하여 동작을 조정하거나 처리하도록 설계되어 있습니다.
Annotation은 마치 수정자처럼 패키지, 클래스, 생성자, 메서드, 필드, 파라미터, 지역 변수 선언에 적용될 수 있으며, 코드의 가독성과 유지보수성을 높이는 데 기여합니다.
내부 구조 및 작동 원리
Annotation은 실질적으로 java.lang.annotation.Annotation 인터페이스를 상속한 특수한 인터페이스입니다. 이는 @interface 키워드로 정의되며, 일반 인터페이스와는 달리 제약 사항이 존재합니다.
- 메서드는 매개변수 없이, 예외를 던지지 않아야 합니다.
- 반환 타입은 기본형,
Class, 열거형, 다른 어노테이션, 또는 이러한 타입의 1차원 배열만 가능합니다. - 기본값은
default키워드로 지정되며,null은 허용되지 않습니다. - 제네릭을 사용할 수 없으며,
Class타입의 메서드만 제네릭을 포함할 수 있습니다.
이러한 제약은 어노테이션이 단순하고 예측 가능한 메타데이터를 제공하기 위함이며, 컴파일러나 리플렉션을 통해 쉽게 분석할 수 있도록 합니다.
주요 사용 사례
어노테이션은 주로 프레임워크 내부에서 사용되며, 다음과 같은 목적을 달성합니다:
- 컴파일 타임 검사 (예:
@Override) - 코드의 비추천 사용 알림 (예:
@Deprecated) - 경고 메시지 억제 (예:
@SuppressWarnings) - 런타임 동작 결정 (예: 스프링의
@Component,@Autowired)
표준 어노테이션 종류
@Override
상위 클래스의 메서드를 재정의했는지 확인하는 마커 어노테이션입니다. 잘못된 이름으로 오버라이딩을 시도하면 컴파일 에러를 발생시킵니다.
@Deprecated
사용이 권장되지 않는 클래스나 멤버를 표시합니다. 컴파일러는 해당 요소를 사용할 경우 경고를 출력하며, 문서화 도구(javadoc)에서도 이 정보를 반영합니다.
@SuppressWarnings
특정 경고를 무시하도록 지시합니다. 예를 들어, 타입 캐스팅 경고("unchecked")나 불필요한 코드 흐름 경고("fallthrough") 등을 제거할 수 있습니다.
@SuppressWarnings({"unchecked", "fallthrough"})
public void process() {
// ...
}
단일 값인 경우 중괄호 생략 가능:
@SuppressWarnings("unchecked")
사용자 정의 어노테이션 예제
다음은 커스텀 어노테이션을 정의하고 리플렉션을 통해 값을 추출하는 예제입니다.
1. Author.java
package com.magc.annotation;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@Documented
public @interface Author {
String name();
String group();
}
2. Description.java
package com.magc.annotation;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
public @interface Description {
String value();
}
3. Utility.java
package com.magc.annotation;
@Description(value = "이 클래스는 유틸리티 기능을 제공합니다.")
public class Utility {
@Author(name = "haoran_202", group = "com.magc")
public String execute() {
return "작업 완료";
}
}
4. AnalysisAnnotation.java
package com.magc.annotation;
import java.lang.reflect.Method;
public class AnalysisAnnotation {
public static void main(String[] args) {
try {
Class<?> clazz = Class.forName("com.magc.annotation.Utility");
Method[] methods = clazz.getMethods();
if (clazz.isAnnotationPresent(Description.class)) {
Description desc = clazz.getAnnotation(Description.class);
System.out.println("설명: " + desc.value());
}
for (Method method : methods) {
if (method.isAnnotationPresent(Author.class)) {
Author author = method.getAnnotation(Author.class);
System.out.println("저자: " + author.name() + " (" + author.group() + ")");
}
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
실행 결과:
설명: 이 클래스는 유틸리티 기능을 제공합니다.
저자: haoran_202 (com.magc)