애너테이션이란?
- 주석처럼 프로그래밍 언어에 영향을 미치지 않고, 유용한 정보를 제공
- 원래 소스코드와 문서가 따로 있었지만 관리하기 편하게 하기 위해서 소스코드 + 문서를 합침
- 프로그램의 소스코드 안에 다른 프로그램을 위한 정보를 미리 약속된 형식으로 포함시킨 것
- 애너테이션의 사용예

- Java에서 제공하는 애너테이션

-> 메타애너테이션(@Target*, @Documented, @inherited, @Retention, @Repeatable): 애너테이션을 만들 때 사용하는 애너테이션
표준애너테이션
1. @Override
- 오버라이딩을 올바르게 했는지 컴파일러가 체크하게 한다.(for javac.exe)
- 오버라이딩 할 때 메서드 이름을 잘못 적는 실수를 하는 경우가 많기 때문에


class Parent {
void parentMethod() {}
}
class Child extends Parent {
@Override
// void parentmethod() {} // 에러
void parentMethod() {}
}
2. @Deprecated
- 앞으로 사용하지 않을 것을 권장하는 필드나 메서드에 붙인다.
- @Deprecated의 사용 예, Date 클래스의 getDate( )

-> 자바는 하휘호환성을 중요하기 때문에 없애지는 않고, 사용을 권장하지 않음.
- @Deprecated가 붙은 대상이 사용된 코드를 컴파일 하면 경고가 나타남. 글자중간에 작대기
3. @FunctionalInterface
- 함수형 인터페이스에 붙이면, 컴파일러가 올바르게 작성했는지 체크(for javac.exe)
- 함수형 인터페이스에는 하나의 추상메서드만 가져야 한다는 제약이 있음

-> 함수형 인터페이스 안에 0개나 2개의 추상메서드가 있다면 오류!
-> @Override 처럼 사용 안해도 되지만, 실수오류를 제거할 수 있음
@FunctionalInterface // 함수형 인터페이스는 하나의 추상메서드만 가능
interface Testable {
void test();
// void check();
}
4. @SuppressWarnings
- 컴파일러의 경고메시지가 나타나지 않게 억제한다.
- 괄호( )안에 억제하고자 하는 경고의 종류를 문자열로 지정
@SuppressWarnings("unchecked") // 지네릭스와 관련된 경고를 억제
ArrayList list = new ArrayList( ); // 지네릭 타입을 지정하지 않았음
list.add(obj); // 여기서 경고가 발생
-> ArrayList는 지네릭클래스인데 이 코드에서 지네릭타입<T>을 지정하지 않아서 “unchecked” 경고발생
-> @SuppressWarnings을 사용하는 이유는 경고를 확인했다는 의미. 컴파일러가 알려주는 경고를 보고 애너테이션을 추가
- 둘 이상의 경고를 동시에 억제하려면 다음과 같이 한다.
@SuppressWarnings({"deprecation", "unchecked", "varargs")}
메타 애너테이션
- ‘애너테이션을 위한 애너테이션’ -> 애너테이션을 만들 때 사용함
- 메타 애너테이션은 java.lang.annotiation 패키지에 포함
| 애너테이션 | 설명 |
| @Target | 애너테이션이 적용가능한 대상을 지정하는데 사용 |
| @Documented | 애너테이션 정보가 javadoc으로 작성된 문서에 포함되게 한다. |
| @Inherited | 애너테이션이 자손 클래스에 상속되도록 한다. |
| @Retention | 애너테이션이 유지되는 범위를 지정하는데 사용한다. |
| @Repeatable | 애너테이션을 반복해서 적용할 수 있게 한다. |
1. @Target
- 애너테이션을 정의할 때, 적용대상 지정에 사용


-> MyAnnotation이라는 애너테이션을 정의(public @interface MyAnnotation { })
-> 이 애너테이션 안에는 FIELD, TYPE, TYPE_USE만 사용 가능(@Target({FIELD, TYPE, TYPE_USE}))
-> FIELD: 필드(iv, cv 등) , TYPE: 클래스, 인터페이스 등 , TYPE_USE: 타입이 사용되는 모든 곳(클래스, 인터페이스 안)
2.@Retention
- 애너테이션이 유지(retention)되는 기간을 지정하는데 사용

-> SOURCE와 RUNTIME을 주로 사용
- 컴파일러에 의해 사용되는 애너테이션의 유지 정책은 SOURCE이다.
-> @Override 애너테이션은 컴파일러가 오버라이딩을 제대로 하는지 체크하기 때문에 SOURCE 사용(클래스파일에 굳이 존재하지 않아도 됨)

- 실행시에 사용 가능한 애너테이션의 정책은 RUNTIME이다.
-> 유지 정책을 ‘RUNTIME’으로 하면, 실행 시에 ‘리플랙션(reflection)’을 통해 클래스 파일에 저장된 애너테이션의 정보를 읽어서 처리할 수 있다.
-> @FunctionalInterface는 @Override처럼 컴파일러가 체크해주는 애너테이션이지만, 실행 시에도 사용되어서 유지정책이 RUNTIME이다.

3. @Documented, @Inherited
- javadoc으로 작성한 문서에 포함시키려면 @Documented를 붙인다.

- 애너테이션을 자손 클래스에 상속하고자 할 때, @Inherited를 붙인다.

-> 두 애너테이션 모두 다 잘 사용되지는 않는다.
4. @Repeatable
- 반복해서 붙일 수 있는 애너테이션을 정의할 때 사용

- @Repeatable이 붙은 애너테이션은 반복해서 붙일 수 있다.(하나의 대상에 애너테이션을 여러 번 붙일 수 있다. )

- @Repeatable인 @ToDo를 하나로 묶을 컨테이너 애너테이션도 정의해야 함

애너테이션 타입 정의하기
애너테이션 만드는 방법

@interface DateTime {
String yymmdd( ); // 날짜
String hhmmss( ); // 시간
}
- 애너테이션의 메서드는 추상 메서드이며, 애너테이션을 적용할 때 지정(순서 X)


애너테이션의 요소
- 적용시 값을 지정하지 않으면, 사용될 수 있는 기본값 지정 가능(null제외)

- 요소의 한 개의 이름이 value일 때만 생략 가능함.

- 요소의 타입이 배열인 경우, 괄호{ }를 사용해야 한다


-> 배열일 때 요소가 한 개이면 { }가 생략가능 하지만, 여러 개 일 경우 { } 필요
-> default는 값은 { } ( 빈 괄호 { } )
모든 애너테이션의 조상
- java.lang.annotation.Annotation
- Annotation은 모든 애너테이션의 조상이지만 상속은 불가, Annotation은 인터페이스이기 때문

-> Annotation에 있는 추상메서드를 구현하지 않고도 사용 가능!(컴파일러가 자동으로 추상메서드 구현)
마커 애너테이션 - Marker Annotation
- 요소가 하나도 정의되지 않은 애너테이션(값을 지정할 필요가 없다.)

애너테이션 요소의 규칙
-> 요소의 타입은 기본형, String, enum, 애너테이션, Class(설계도 객체)만 허용됨
-> 괄호( )안에 매개변수를 선언할 수 없다. (추상메서드)
-> 예외를 선언할 수 없다.
-> 요소를 타입 매개변수로 정의할 수 없다. <T>
@interface AnnoTest {
int id = 100; // OK 상수선언, static final int id = 100;
String major(int i, int j); // 에러. 매개변수를 선언할 수 없음
String minor( ) throws Exception; // 에러. 예외선언을 할 수 없음
ArrayList<T> list ( ); // 에러. 요소의 타입에 타입 매개변수 사용 불가
}
예제)
import java.lang.annotation.*;
@Retention(RetentionPolicy.RUNTIME) // 실행 시에 사용가능하도록 지정
@interface TestInfo { // TestInfo 애너테이션 생성
int count() default 1;
String testedBy();
String[] testTools() default "JUnit";
TestType testType() default TestType.FIRST;
DateTime testDate();
}
@Retention(RetentionPolicy.RUNTIME) // 실행 시에 사용가능하도록 지정
@interface DateTime { // DateTime 애너테이션 생성
String yymmdd();
String hhmmss();
}
enum TestType { FIRST, FINAL } // 열거형
@Deprecated // 사용 권장 안함
@SuppressWarnings("1111") // 유효하지 않은 애너테이션은 무시된다.
@TestInfo(testedBy="aaa", testTools = {"JUnit","JUnit5"},testDate = @DateTime(yymmdd="160101",hhmmss="235959"))
//@TestInfo에서 default값은 적지 않아도 됨
class Ex12_8 {
public static void main(String args[]) {
Class<Ex12_8> cls = Ex12_8.class;
TestInfo anno = cls.getAnnotation(TestInfo.class);
System.out.println("anno.testedBy() = "+anno.testedBy());
System.out.println("anno.testDate().yymmdd()=" + anno.testDate().yymmdd());
System.out.println("anno.testDate().hhmmss()=" + anno.testDate().hhmmss());
for(String str:anno.testTools())
System.out.println("testTools="+str);
System.out.println();
// Ex12_8에 적용된 모든 애너테이션을 가져온다.
Annotation[] annoArr = cls.getAnnotations();
for(Annotation a : annoArr)
System.out.println(a);
}// main의 끝
}'멀티캠퍼스 풀스택 과정 > Java의 정석' 카테고리의 다른 글
| 자바의 정석10-2 싱글쓰레드와 멀티쓰레드, 쓰레드의 I/O 블락킹 (0) | 2022.01.12 |
|---|---|
| 자바의 정석10-1 프로세스와 쓰레드 (0) | 2022.01.12 |
| 자바의 정석9-3 열거형(enum) (0) | 2022.01.12 |
| 자바의 정석9-2 와일드 카드, 지네릭 메서드 (1) | 2022.01.12 |
| 자바의 정석9-1 지네릭스 (0) | 2022.01.12 |