메타데이터
: 데이터에 대한 데이터, 즉 다른 데이터를 설명해주는 데이터이다.
( ex. 카메라로 사진을 찍었을 때 사진에 대한 촬영한 시간, 장소, 카메라 모델명, 플래쉬 사용 유무, 등등
이 메타데이터라고 할 수 있다. )
애너테이션의 용도
자바 리플렉션
: 구체적인 클래스 타입을 알지 못해도 그 클래스의 메소드, 타입, 변수들에 접근할 수 있도록 해주는 자바 API이다.
런타임 시에 클래스 이름만 알고 있다면 클레스에 대한 정보를 가져오고 활용할 수 있게 해준다.
클래스이름.class를 이용해서 클래스의 필드, 생성자, 메서드에 대한 정보를 얻을 수 있다.
메서드명 | 리턴타입 | 설명 |
---|---|---|
getFields() | Field[] | 접근 제어자가 public인 필드들을 Field 배열로 반환. 부모 클래스의 필드들도 함께 반환한다. |
getConstructors() | Constructor[] | 접근 제어자가 public인 생성자들을 Constructor 배열로 반환. 부모 클래스의 생성자들도 함께 반환한다. |
getMethods() | Method[] | 접근 제어자가 public인 메서드들을 Method 배열로 반환. 부모 클래스의 메서드들도 함께 반환한다. |
getDeclaredFields() | Field[] | 접근 제어자에 상관없이 모든 필드들을 Field배열로 반환. 부모 클래스의 필드들은 반환하지 않는다. |
getDeclaredConstructors() | Constructor[] | 접근 제어자에 상관없이 모든 생성자들을 Constructor배열로 반환. 부모 클래스의 생성자들은 반환하지 않는다. |
getDeclaredMethod() | Method[] | 접근 제어자에 상관없이 모든 메서드들을 Method배열로 반환. 부모 클래스의 메서드들은 반환하지 않는다. |
애노테이션 정보를 얻기위한 메서드들.
리턴타입 | 메서드명 | 설명 |
---|---|---|
boolean | isAnnotationPresent(Class<? Extends Annotation> annotationClass) | 지정한 애노테이션이 적용되었는지 여부를 확인. Class에서 호출했을 경우 상위 클래스에 적용된 경우에도 true를 리턴. |
Annotation | getAnnotation(Class annotationClass) | 지정한 애노테이션이 적용되어 있으면 애노테이션을 반환하고 그렇지 않은 경우 null을 반환한다. Class에서 호출한 경우 상위 클래스에 적용된 애노테이션도 반환한다. |
Annotation[] | getAnnotations() | 적용된 모든 애노테이션을 반환한다. Class에 사용됐을 경우 상위 클래스에 적용된 애노테이션까지 전부 포함해서 반환한다. 애노테이션이 없을 경우 길이가 0인 배열을 반환한다. |
Annotation[] | getDeclaredAnnotation() | 직접 적용된 모든 애노테이션을 리턴한다. Class에서 호출했을 경우 상위 클래스에 적용된 애노테이션은 포함되지 않는다.(상위 클래스의 @Inherited가 붙은 애노테이션을 무시한다.) |
public @interface MyAnnotation{
}
🔺애너테이션을 직접 정의하는 방법이다.
@interface'는 애너테이션 타입(annotation type)을 선언하는 키워드다.
애너테이션 타입 선언을 일반적인 인터페이스(interface) 선언과 구분하기 위해 interface 앞에 기호 @를 붙인다.
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface MyAnnotation{
int number() default 500; // int 타입(기본형)
String value(); // String
String[] arr(); // 배열로 생성
Operation opration(); // Enum 타입
Class cc(); // Class 타입
Target t(); // Target 애너테이션
}
🔺애너테이션 필드종류는 위와 같이 선언이 가능하고, 각각 요소에 값을 줘서 아래와 같이 사용할 수 있다.
public class MyClass{
@MyAnnotation
value = "java study",
arr = {"park", "kim", "lee"},
operation = Operation.DIVIDE,
cc = MyClass.class,
t = @Target(ElementType.ANNOTATION_TYPE))
public void method() {
}
public static void main(String[] args) {
}
}
애너테이션 | 설명 |
---|---|
@Target | 애너테이션이 적용가능한 대상을 지정하는데 사용한다. |
@Documented | 애너테이션 정보가 javadoc으로 작성된 문서에 포함되게 한다. |
@Inherited | 애너테이션이 자손 클래스에 상속되도록 한다. |
@Retention | 애너테이션이 유지되는 범위를 지정하는데 사용한다. |
@Repeatable | 애너테이션을 반복해서 사용할 수 있게 한다. (JDK 1.8) |
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Target{
ElementType[] value();
}
🔺@Target 애너테이션 실제 코드
ElementType의 Enum 요소를 사용해서 애너테이션이 적용 가능한 대상을 결정한다.
@Target({ElementType.TYPE, ElementType.FIELD, ElementType.METHOD})
요소타입이 ElementType[] 배열이기 때문에 적용가능한 대상을 여러 개의 값을 지정할 수 있다.
✅@Target으로 지정할 수 있는 애너테이션 적용대상의 종류
ElementType | 대상 타입 |
---|---|
ANNOTATION_TYPE | 애너테이션 |
CONSTRUCTOR | 생성자 |
FIELD | 필드(멤버변수, enum상수) |
LOCAL_VARIABLE | 지역변수 |
METHOD | 메서드 |
PACKAGE | 패키지 |
PARAMETER | 매개변수 |
TYPE | 타입(클래스, 인터페이스, enum) |
TYPE_PARAMETER | 타입 매개변수 |
TYPE_USE | 타입이 사용되는 곳(타입의 변수를 선언할 때) |
@ExAnnotation // ElementType.TYPE
public class ExClass {
@ExAnnotation // ElementType.FIELD
int num;
@ExAnnotation // ElementType.TYPE_USE
ExClass ec;
@ExAnnotation // ElementType.METHOD
public void method() {
}
}
javadoc
으로 작성한 문서에 포함되도록 한다.
//Documented를 포함한 사용자 정의 어노테이션
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
public @interface CustomA {
String testDocument();
}
//@Documented를 포함하지 않는 사용자 정의 어노테이션
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
public @interface CustomB {
String testNoDocument();
}
✅애너테이션의 유지 정책(Retention policy)의 종류
유지정책 | 의미 |
---|---|
SOURCE | 소스 파일에만 존재. 클래스 파일에는 존재하지 않음 |
CLASS | 클래스 파일에 존재. 실행시에 사용 불가. Default 값 |
RUNTIME | 클래스 파일에 존재. 실행시에 사용가능 |
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Retention{
RetentionPolicy value();
}
🔺@Retention 애너테이션 실제 코드
RetentionPolicy의 값을 넘겨주는 것으로 애너테이션의 유지 정책이 결정된다고 볼 수 있다.
RetetionPolicy는 유지정책 3가지를 지니고 있는 Enum 형태를 갖고 있다.
SOURCE
이다.
// @ToDo 애너테이션을 여러 번 반복해서 쓸 수 있게 한다.
@Repeatable(Todos.class)
@interface Todo {
String value();
}
🔺@ToDo라는 애너테이션이 위와 같이 정의되어 있을 때, 특정 클래스에 ToDo 애너테이션을
여러 번 붙이는 것이 가능하다.
@ToDo("delete test codes.")
@ToDo("override inherited methods")
class MyClass{
}
🔺일반적인 애너테이션과 달리, 같은 이름의 애너테이션이 여러개가 하나의 대상에 적용될 수 있기 때문에,
해당 애너테이션들을 하나로 묶어서 다룰 수 있는 애너테이션도 추가로 정의해야 한다.
위 예졔의 경우 Todos.class가 그 역할을 한다.
@interface ToDos{ // 여러 개의 ToDo 애너테이션을 담을 컨테이너 애너테이션
ToDo[] value(); // ToDo애너테이션 배열타입의 요소를 선언. "이름이 반드시 value"
}
@Repeatable(ToDos.class)
@interface ToDo{
String value();
}
애너테이션 | 설명 |
---|---|
@Override | 컴파일러에게 오바리이딩하는 메서드라는 것을 알린다. |
@Deprecated | 앞으로 사용하지 않을 것을 권장하는 대상에 붙인다. |
@FunctionalInterface | 함수형 인터페이스라는 것을 알린다. (JDK 1.8) |
@SuppressWarnings | 컴파일러의 특정 경고메시지가 나타나지 않게 해준다. |
@SafeVarargs | 제네릭스 타입의 가변인자에 사용한다. (JDK 1.7) |
@Native | native 메서드에서 참조되는 상수 앞에 붙인다. (JDK 1.8) |
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.SOURCE)
public @interface Override
🔺@Override 애너테이션 실제 코드
public class Annotation {
// 에러없음, 단지 새로운 메서드라고 감지
public String tString() {
return "";
}
// 에러감지
// java: method does not override or implement a method from a supertype
@Override
public String rString() {
return "";
}
}
@Deprecated
public int getDate() {
return normalize().getDayOfMonth();
}
@FunctionalInterface
public interface Runnable {
/**
* When an object implementing interface <code>Runnable</code> is used
* to create a thread, starting the thread causes the object's
* <code>run</code> method to be called in that separately executing
* thread.
* <p>
* The general contract of the method <code>run</code> is that it may
* take any action whatsoever.
*
* @see java.lang.Thread#run()
*/
public abstract void run();
}
✅@SuppressWarnings의 토큰종류
(@SuppressWarnings("토큰") 형태로 사용한다.)
토큰 | 설명 |
---|---|
all | 모든 경고를 억제합니다. |
boxing | 오퍼레이션과 관련된 경고를 억제합니다. |
cast | 캐스트 오퍼레이션과 관련된 경고를 억제합니다. |
dep-ann | 권장되지 않는 애노테이션과 관련된 경고를 억제합니다. |
deprecation | 권장되지 않는 기능과 관련된 경고를 억제합니다. (@Deprecated) |
fallthrough | switch문에서 누락된 break 문과 관련된 경고를 억제합니다. |
finally | 리턴되지 않는 마지막 블록과 관련된 경고를 억제합니다. |
hiding | 변수를 숨기는 로컬과 관련된 경고를 억제합니다. |
incomplete-switch | switch 문에서 누락된 항목과 관련된 경고를 억제합니다.(enum case) |
javadoc | javadoc 경고와 관련된 경고를 억제합니다. |
null | 널(null) 분석과 관련된 경고를 억제합니다. |
rawtypes | 원시 유형 사용법과 관련된 경고를 억제합니다. |
restriction | 올바르지 않거나 금지된 참조 사용법과 관련된 경고를 억제합니다. |
resource | 닫기 가능 유형의 자원 사용에 관련된 경고 억제합니다. |
serial | 직렬화 가능 클래스에 대한 누락된 serialVersionUID필드와 관련된 경고를 억제합니다. |
static-access | 잘못된 정적 액세스와 관련된 경고를 억제합니다. |
static-method | static으로 선언될 수 있는 메서드와 관련된 경고를 억제합니다. |
super | 슈퍼 호출을 사용하지 않는 메서드 오버라이딩과 관련된 경고를 억제합니다. |
synthetic-access | 내부 클래스로부터의 최적화되지 않은 액세스와 관련된 경고를 억제합니다. |
sync-override | 동기화된 메서드를 오버라이드하는 경우 누락된 동기화로 인한 경고 억제합니다. |
unchecked | 미확인 오퍼레이션과 관련된 경고를 억제합니다. |
unqualified-field-access | 규정되지 않은 필드 액세스와 관련된 경고를 억제합니다. |
unused | 사용하지 않은 코드 및 불필요한 코드와 관련된 경고를 억제합니다. |
class MyThread extends Thread {
@SuppressWarnings("deprecation") // 에러 메시지 억제
@Override
public void run() {
stop();
}
}
🔺@SuppressWarnings 애너테이션 토큰사용 예시
unchecked
경고가 발생한다.비 구체화 타입(non-reifiable type)
- 컴파일 후에 제거되는 타입(런타임에 구체화되지 않는다.)
- 컴파일 후에 타입 정보가 유지되지 않는다는 의미이다.
구체화 타입(reifiable type)
- 컴파일 후에도 제거되지 않는 타입(런타임에 구체화된다.)
- 컴파일 후에도 타입 정보가 유지된다는 의미이다.
@SafeVarargs // unchecked 억제
@SuppressWarnings("varargs") // vargars 억제
public static <T> List<T> asList(T... var0) {
return new Arrays.ArrayList(var0);
}
🔺java.utill.Arrays의 asList()는 위처럼 정의되어 있으며, 이 메서드는 매개변수로 넘겨받은 값들로 배열을
만들어서 새로운 ArrayList 객체를 만들어서 반환하는데 이 과정에서 "unchecked"경고가 발생한다.