컴파일 과정과 실행 과정에서 코드를 어떻게 컴파일하고 처리할지 알려주는 메타데이터 정보
| 사용 용도 |
| 컴파일러에게 코드 문법 에러를 체크하도록 정보 제공 |
| 소프트웨어 개발 툴이 빌드나 배치 시 코드를 자동으로 생성할 수 있도록 정보 제공 |
| 실행 시 (런타임 시) 특정 기능을 실행하도록 정보를 제공 |
ex) @Override : 메소드가 오버라이드 된 것임을 컴파일러에게 알려 컴파일러가 오버라이드 검사하도록 함 / 정확히 오버라이드 되지 않았다면 에러 발생 / 빌드 시 자동으로 XML 설정 파일을 생성 / 배포를 위해 JAR 압축 파일을 생성함 / 실행 시 클래스의 역할을 정의
어노테이션 타입 정의와 적용
public @interface 어노테이션 {
타입 elementName() [default 값];
}
- 어노테이션은 엘리먼트를 멤버로 가질 수 있으며, 각 엘리먼트는 타입과 이름으로 구성되고 디폴트 값을 가질 수 있음
- 엘리먼트의 타입으로는 int, double 같은 기본 데이터 타입, String, 열거 타입, Class 타입, 이들의 배열 타입을 사용 가능
- 엘리먼트 이름 뒤 메소드처럼 ()를 붙여야 함
public @interface AnnotationName {
String value();
int elementName() default 5;
}
@AnnotationName("값");
또는
@AnnotationName(value = "값", elementName = 3);
- 디폴트 값이 없다면 반드시 값을 기술해야 하고 있으면 생략 가능
- value 엘리먼트를 가진 어노테이션은 코드에 적용할 때 엘리먼트 이름을 입력하지 않아도 됨
어노테이션 적용 대상
- java.lang.annotation,ElementType 열거 상수로 아래 표와 같이 정의 되어있음
| ElementType 열거 상수 | 적용 대상 |
| TYPE | 클래스, 인터페이스, 열거 타입 |
| ANNOTATION_TYPE | 어노테이션 |
| FIELD | 필드 |
| CONSTRUCTOR | 생성자 |
| METHOD | 메소드 |
| LOCAL_VARIABLE | 로컬 변수 |
| PACKAGE | 패키지 |
- @Target : 어노테이션이 적용될 대상을 지정할 때 사용 / @Target의 기본 엘리먼트인 value는 ElementType 배열을 값으로 가짐
@Target({ElementType.TYPE, ElementType.FIELD, ElementType.METHOD})
public @interface AnnotationName {
}
- 클래스, 필드, 메소드에서만 어노테이션 적용 가능
어노테이션 유지 정책
- 어노테이션을 소스상에서만 유지할 건지, 컴파일된 클래스까지 유지할 건지, 런타임 시에도 유지할 건지 유지 범위를 지정해야 함
- java.lang.annotation.RetentionPolicy 열거 상수로 아래 표와 같이 정의 되어 있음
| RetentionPolicy 열거 상수 | 설명 |
| SOURCE | 소스상에서만 어노테이션 정보를 유지 / 소스 코드를 분석할 떄만 의미 있음 |
| CLASS | 바이트 코드 파일까지 어노테이션 정보 유지 / 리플렉션을 이용해 어노테이션 정보를 얻을 수 없음 |
| RUNTIME | 바이트 코드 파일까지 어노테이션 정보를 유지하며 리플렉션을 이용해 런타임 시 어노테이션 정보를 얻을 수 있음 |
- 리플렉션 : 런타임 시에 클래스의 메타 정보를 얻는 기능 / 클래스가 가지고 있는 필드가 무엇인지, 어떤 생성자, 메소드를 가지고 있는지, 적용된 어노테이션이 무엇인지 / 어노테이션 유지 정책을 RUNTIME으로 설정해야 사용 가능
@Target({ElementType.TYPE, ElementType.FIELD, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface AnnotationName{
}
런타임 시 어노테이션 정보 사용하기
- 리플렉션을 이용해 어노테이션의 적용 여부와 엘리먼트 값을 읽고 적절히 처리 가능
- 어노테이션 정보를 얻기 위해선 java.lang.Class 이용
- 필드, 생성자, 메소드에 적용된 어노테이션 정보를 얻기 위해선 java.lang.reflect 패키지의 Field, Constructor, Method 타입의 배열을 얻어야 함
| 리턴 타입 | 메소드명(매개 변수) | 설명 |
| Field[] | getField() | 필드 정보를 Field 배열로 리턴 |
| Constructor[] | getConstructor() | 생성자 정보를 Constructor 배열로 리턴 |
| Method[] | getMethod() | 메소드 정보를 Method 배열로 리턴 |
- 배열을 얻은 후 아래 표의 메소드를 호출하여 적용된 어노테이션 정보를 얻을 수 있음
| 리턴 타입 | 메소드명(매개 변수) |
| boolean | isAnnotationPresent(Class<? extends Annotation> annotationClass) |
| 지정한 어노테이션이 적용되었는지 여부, Class에서 호출했을 때 상위 클래스에 적용된 경우에도 true 리턴 | |
| Annotation | getAnnotation(Class<T> annotationClass) |
| 지정한 어노테이션이 적용되어 있으면 어노테이션 리턴, 그렇지 않다면 null 리턴 / Class에서 호출했을 때 상위 클래스에 적용된 경우에도 어노테이션 리턴 | |
| Annotation[] | getAnnotations() |
| 적용된 모든 어노테이션을 리턴 / Class에서 호출했을 때 상위 클래스에 적용된 어노테이션도 모두 포함 / 적용된 어노테이션이 없을 경우 길이가 0인 배열 리턴 | |
| Annotation[] | getDeclaredAnnotations() |
| 직접 적용된 모든 어노테이션을 리턴 / Class에서 호출했을 때 상위 클래스에 적용된 어노테이션은 제외 |
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface PrintAnnotation {
String value() default "-";
int number() default 15;
}
public class Service {
@PrintAnnotation
public void method1() {
System.out.println("실행 내용1");
}
@PrintAnnotation("*")
public void method2() {
System.out.println("실행 내용2");
}
@PrintAnnotation(value = "#", number = 20)
public void method3() {
System.out.println("실행 내용3");
}
}
public class Example {
public static void main(String[] args) {
// Service 클래스로부터 메소드 정보를 얻음
Method[] declaredMethods = Service.class.getDeclaredMethods(); // Service 클래스에 선언된 메소드 얻기 (리플렉션)
// Method 객체를 하나씩 처리
for (Method method : declaredMethods) {
// PrintAnnotation이 적용되었는지 확인
if (method.isAnnotationPresent(PrintAnnotation.class)) {
// PrintAnnotation 객체 얻기
PrintAnnotation printAnnotation = method.getAnnotation(PrintAnnotation.class);
// 메소드 이름 출력
System.out.print("[" + method.getName() + "]");
// 구분선 출력
for (int i = 0; i < printAnnotation.number(); i++) {
System.out.print(printAnnoation.value());
}
System.out.println();
try {
// 메소드 호출
method.invoke(new Service());
} catch (Exception e) {}
System.out.println();
}
}
}
}
출력 결과 :
[method1]
---------------
실행 내용1
[method2]
***************
실행 내용2
[method3]
####################
실행 내용3
'언어 > Java' 카테고리의 다른 글
| 메소드 재정의 (오버라이딩) (0) | 2023.08.24 |
|---|---|
| 상속 (0) | 2023.08.24 |
| Getter와 Setter (0) | 2023.08.23 |
| 접근 제한자 (0) | 2023.08.23 |
| 클래스 (2) | 2023.08.23 |