1. 어노테이션 (Annotation)
@AnnotationName
- 어노테이션 = 메타데이터
- 메타데이터란 애플리케이션이 처리해야 할 데이터가 아니라, 컴파일 과정과 실행 과정에서 코드를 어떻게 컴파일하고 처리할 것인지 알려주는 정보입니다.
- 직접 정의해서 사용할 일은 크게 없지만 스프링 프레임워크를 사용한다면 자주 사용하게 되므로 읽을 줄은 알아야 할 것을 권장합니다.
2. 어노테이션의 용도
1) 컴파일러에게 코드 문법 에러를 체크하도록 정보를 제공(RetentionPolicy.SOURCE)
2) 소프트웨어 개발 툴이 빌드나 배치 시 코드를 자동으로 생성할 수 있도록 정보를 제공(RetentionPolicy.CLASS)
3) 실행 시(런타임 시) 특정 기능을 실행하도록 정보를 제공(RetentionPolicy.RUNTIME)
Ex) @Override
메소드 선언 시 사용하며,
메소드가 오버라이드(재정의)된 것임을 컴파일러에게 알려주어 컴파일러가 오버라이드 검사를 하도록 해줍니다.
정확히 오버라이드가 되지 않았다면 컴파일러는 에러를 발생시킵니다.
그 외에 다음과 같이 사용합니다. (스프링 프레임워크에서 많이 볼 수 있습니다.)
1) 빌드 시 자동으로 XML 설정 파일을 생성
2) 배포를 위해 JAR 압축 파일을 생성
3) 실행 시 클래스의 역할을 정의
3. 어노테이션 타입 정의와 사용
정의
public @interface AnnotationName {
}
사용
@AnnotationName
element
어노테이션은 element를 멤버로 가질 수 있습니다.
각 엘리먼트는 타입과 이름으로 구성되며, 디폴트 값을 가질 수 있습니다.
엘리먼트 타입으로는 기본 데이터 타입이나 참조 데이터 타입을 사용할 수 있습니다.
public @interface AnnotationName {
타입 elementName() [default 값];
}
예시
어노테이션 정의
public @interface DefaultValues {
int defaultNumber();
String defaultString() default "hello annotation";
}
어노테이션 사용
@DefaultValues(defaultNumber = 7) // 기본 값이 있는 element는 생략 할 수 있습니다.
//@DefaultValues(defaultNumber = 7, defaultString = "bye annotation")
public class Main {
}
value element
value()
기본 엘리먼트 입니다.
기본 엘리먼트는 엘리먼트 이름 없이 값만 이용하여 사용할 수 있습니다.
예시
어노테이션 정의
public @interface DefaultValues {
int value();
String defaultString() default "hello annotation";
}
어노테이션 사용
@DefaultValues(7) // value 엘리먼트는 값만 지정할 수 있습니다.
//@DefaultValues(value = 7, defaultString = "bye annotation") // 다른 엘리먼트도 값을 변경하고 싶다면 엘리먼트 이용을 작성해야 합니다.
public class Main {
}
4. 어노테이션 적용 대상
@Target 어노테이션과 java.lang.annotation.ElementType 열거 상수를 이용해 어노테이션을 사용할 수 있는 적용 대상을 설정합니다.
public enum ElementType {
/** 적용 대상: Class, interface, enum */
TYPE,
/** 적용 대상: Field */
FIELD,
/** 적용 대상: Method */
METHOD,
/** 적용 대상: Formal parameter */
PARAMETER,
/** 적용 대상: Constructor */
CONSTRUCTOR,
/** 적용 대상: Local variable */
LOCAL_VARIABLE,
/** 적용 대상: Annotation type */
ANNOTATION_TYPE,
/** 적용 대상: Package */
PACKAGE,
/**
* 적용 대상: Type parameter
*
* @since 1.8
*/
TYPE_PARAMETER,
/**
* Use of a type
*
* @since 1.8
*/
TYPE_USE,
/**
* Module declaration.
*
* @since 9
*/
MODULE
}
예시
1) 하나의 대상을 지정
@Target(ElementType.TYPE) // 클래스, 인터페이스, 열거 타입만 사용가능
public @interface DefaultValues {
int value();
String defaultString() default "hello annotation";
}
2) 여러 대상을 지정할 경우 {} 안에 지정합니다. (ElementType[])
@Target({ElementType.FIELD, ElementType.CONSTRUCTOR}) // 필드, 생성자만 사용가능
public @interface DefaultValues {
int value();
String defaultString() default "hello annotation";
}
이유는 Target 어노테이션이 배열로 값을 받기 때문입니다.
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Target {
/**
* Returns an array of the kinds of elements an annotation type
* can be applied to.
* @return an array of the kinds of elements an annotation type
* can be applied to
*/
ElementType[] value();
}
5. 어노테이션 유지 정책
@Retention 어노테이션과 java.lang.annotation.RententionPolicy 열거 상수를 이용해 어노테이션을 어느 범위까지 유지할 것인지 설정합니다.
public enum RetentionPolicy {
/**
* 소스상에서만 어노테이션 정보를 유지
* 소스 코드를 분석할 때만 의미가 있으며, 바이트 코드 파일에는 정보가 남지 않습니다.
*/
SOURCE,
/**
* 바이트 코드 파일까지 어노테이션 정보를 유지
* 리플렉션을 이용해서 어노테이션 정보를 얻을 수 없습니다.
*/
CLASS,
/**
* 바이트 코드 파일까지 어노테이션 정보를 유지
* 리플렉션을 이용해서 런타임 시에 어노테이션 정보를 얻을 수 있습니다.
* 리플렉션: 런타임 시에 클래스의 메타 정보를 얻는 기능
* Class 객체를 이용해서 클래스의 생성자, 필드, 메소드 정보, 적용된 어노테이션 정보를 알아낼 수 있습니다.
*/
RUNTIME
}
예시
@Retention(RetentionPolicy.RUNTIME) // 런타임 유지
public @interface DefaultValues {
int value();
String defaultString() default "hello annotation";
}
6. 어노테이션 사용하기(런타임 정책)
- 어노테이션 자체는 아무런 동작을 가지지 않는 표식입니다.
- 리플렉션을 이용해서 어노테이션의 적용 여부와 엘리먼트 값을 읽고 적절히 처리할 수 있습니다.
- 클래스에 적용된 어노테이션 정보를 얻으려면 java.lang.Class를 이용합니다.
- 필드, 생성자, 메소드에 적용된 어노테이션 정보를 얻으려면 Class의 메소드를 이용하여 java.lang.reflect 패키지의 Field, Constructor, Method 타입의 배열을 얻어야 합니다.
관련 메소드
[클래스 정보 메소드 → java.lang.Class ]
Field[] getFields() → 필드 정보 리턴
Constructor[] getConstructors() → 생성자 정보 리턴
Method[] getDeclaredMethods() → 메소드 정보 리턴
[어노테이션 정보 메소드 → java.lang.reflect.*]
boolean isAnnotationPresent(Class<? extends Annotation> annotationClass)
→ 지정한 어노테이션이 적용되었는지 여부(Class에서 호출했을 때 상위 클래스에 적용된 경우에도 true를 리턴)
<T extends Annotation> T getAnnotation(Class<T> annotationClass)
→ 지정한 어노테이션이 적용되어 있으면 어노테이션을 리턴하고 그렇지 않다면 null을 리턴
(Class에서 호출했을 때 상위 클래스에 적용된 경우에도 어노테이션을 리턴)
Annotation[] getAnnotations()
→ 적용된 모든 어노테이션을 리턴(Class에서 호출했을 때 상위 클래스에 적용된 어노테이션도 모두 포함)
적용된 어노테이션이 없을 경우 길이가 0인 배열을 리턴
Annotation[] getDeclaredAnnotations() → 직접 적용된 모든 어노테이션을 리턴
(Class에서 호출했을 때 상위 클래스에 적용된 어노테이션은 포함되지 않음)
예시
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.FIELD) // 필드 적용
@Retention(RetentionPolicy.RUNTIME) // 런타임 유지
public @interface DefaultValues {
String value() default "veneas";
}
public class Test {
// 필드에 어노테이션 선언
@DefaultValues()
public String name1;
@DefaultValues("kim")
public String name2;
}
import java.lang.reflect.Field;
public class Main {
public static void main(String[] args) {
// Test 클래스의 필드 정보 얻기
Field[] fields = Test.class.getFields();
for(Field field : fields) {
// 어노테이션 적용 여부 확인
if(field.isAnnotationPresent(DefaultValues.class)) {
// 어노테이션 객체 얻기
DefaultValues defaultValues = field.getAnnotation(DefaultValues.class);
// 적용한 어노테이션의 기본 엘리먼트 출력
System.out.println(defaultValues.value()); // veneas, kim
}
}
}
}
'Backend > 객체 지향 프로그래밍' 카테고리의 다른 글
[Java] final 클래스 final 메소드 (0) | 2022.04.18 |
---|---|
[Java] 클래스 상속 (Inheritance) (0) | 2022.04.17 |
[Java] 객체의 무결성 보호 (Getter, Setter 메소드) (0) | 2022.04.15 |
[Java] 접근 제한자 (Access Modifier) (0) | 2022.04.14 |
[Java] 패키지와 import문 (0) | 2022.04.13 |