이 글은 백기선님의 라이브 스터디 참여 및 학습 내용에 관한 정리한 글입니다.
소스 코드에 대한 문서를 따로 만들기 보단 소스 코드와 문서를 하나의 파일로 관리하는 것이 낫다고 생각했다고 한다. 그래서 개발 시 설명이 필요한 부분은 /** ~ */
안에 해당 로직에 대한 설명을 달고 이러한 주석으로부터 HTML 문서를 생성하는 프로그램(javadoc.exe)을 만들고 사용했다. 이 기능을 응용하여 프로그램 소스코드 안에 다른 프로그램을 위한 정보를 미리 약속된 형식으로 포함시킨 것이 애노테이션이라고 한다. 이 애노테이션은 주석처럼 프로그래밍 언어에 영향을 끼치지 않으면서 다른 프로그램에게 유용한 정보를 제공할 수 있다는 것이 장점이다.
'@' 키워드를 사용하여 선언하게 되며 애노테이션 선언은 일반적으로 인터페이스 선언과 유사하다고 볼 수 있다. '@'키워드라 interface는 별개의 키워드이며 일반적으로 애노테이션을 선언할 때에는 아래과 같이 붙여쓰는 스타일을 권장한다.
public @interface MyChiken {
}
// 이와 같이 띄워쓰기를 해도 프로그램에는 영향을 주진 않는다.
public @ interface MyChiken2 {
}
위 애노테이션은 엄밀히 말하자면 '@MyChiken'이라는 애노테이션이라 명칭하고 '@'를 빼면 'MyChiken' 타입이라고 지칭할 수 있다.
위 애노테이션의 요소들에 대한 예시를 만들어 보자.
public @interface PracticeAnnotation {
int number = 100; // 인터페이스와 동일하게 상수 정의도 가능
String value() default "default값 지정이 된다~"; // default 값을 지정
String[] values(); // 배열도 이용이 가능하다.
TypeTest types(); // 반환타입에 Enum도 사용 가능
MyChiken annotationEl(); // 다른 애노테이션을 포함
}
enum TypeTest {
TEST1, TEST2
}
@interface MyChiken {
String name();
}
애노테이션 요소의 규칙사항
애노테이션의 요소를 정의할 때 반드시 지켜야하는 규칙은 다음과 같다.
- 요소의 타입은 기본형, String, enum(열거체), 애노테이션, Class만 허용
- 요소의 () 안에 매개변수를 선언할 수 없다.
- 예외를 선언할 수 없다.
- 요소를 타입 매개변수로 정의 할 수 없다.
위 규칙들을 어기고 있는 다음 예시를 보면서 이해 해보자.
@interface TestAnnotation {
String test(int num, char ch); // 매개변수는 선언 불가하다.
int test2() throws Exception; // 예외 선언은 불가하다.
List<T> test3(); // 요소의 타압에 타입 매개변수는 사용할 수 없다.
}
모든 애노테이션의 조상은 Anntation이다. 애노테이션은 상속이 허용되지 않으며 명시적으로라도 Anntation 인터페이스를 조상으로 상속 받을 수 없다.
- Anntation 인터페이스를 명시적인 상속했을 때 컴파일 오류가 나는 모습
Annotation 인터페이스 선언부
Annotation 인터페이스는 위와 같이 정의되어 있으며, 모든 애노테이션 객체들은 equals(), hashCode(), toString()와 같은 메소드를 호출하는 것이 가능하다.
값을 지정할 필요가 없는 경우에는 애노테이션의 요소를 정의하지 않아도 된다. 이러한 애노테이션 요소가 하나도 지정되어 있지 않은 애노테이션을 마커 애노테이션이라고 부른다.
- 예시
@interface TestAnno1 {
}
@interface TestAnno2 {
}
메타 애노테이션은 '애노테이션을 위한 애노테이션'이라고 한다. 이 말은 앞서 정리한 '메타 데이터'와 같은 의미이다. 데이터에 대한 데이터 즉 애노테이션에 붙이는 애노테이션으로 애노테이션을 정의할 때 사용되는 것이다.
메타 애노테이션 종류
애노테이션 | 설명 |
---|---|
@Documented | @Documented가 지정된 애노테이션은 javadoc과 같은 도구로 문서화 된다 |
@Target | 애노테이션이 적용가능한 대상을 지정하는데 사용된다 |
@Retention | 애노테이션이 유지되는 기간을 지정하는데 사용된다 |
@Inherited | 애노테이션이 자속 클래스에 상속되도록 한다 |
@Repeatable | 애노테이션을 여러번 붙이는 것이 가능하게 한다 |
@Native | 네이티브 메소드에 의해 참조되는 상수 필드에 붙이는 애노테이션 |
애노테이션이 적용 가능한 대상을 지정하는데 사용되는 애노테이션으로 '@Target' 으로 지정할 수 있는 적용 대상의 종류는 다음과 같습니다.
대상 타입 | 의미 |
---|---|
ANNOTATION_TYPE | 애노테이션 |
CONSTRUCTOR | 생성자 |
FIELD | 필드(멤버변수, enum) |
LOCAL_VARIABLE | 지역변수 |
METHOD | 메소드 |
PACKAGE | 패키지 |
PARAMETER | 매개변수 |
TYPE | 타입(클래스,인터페이스,enum) |
TYPE_PARAMETER | 타입 매개변수(JDK 1.8부터) |
TYPE_USE | 타입이 적용되는 모든 곳(JDK 1.8부터) |
선언부
애노테이션의 요소로 ElementType[] 배열 타입의 value가 선언되어 있는 것을 볼 수 있다.
사용 예시
@Target({FIELD, TYPE, TYPE_USe})
public @interface MyApp {
}
@MyApp // 적용 대상이 TYPE인 경우
class MyClazz {
@MyApp
String value; // 적용 대상이 FIELD인 경우
@MyApp
MyClazz myClazz; // 적용 대상이 TYPE_USE인 경우
}
애노테이션이 유지되는 기간을 지정하는데 사용, 애노테이션을 유지하는 정책의 종류는 다음과 같다.
유지정책 | 설명 |
---|---|
SOURCE | 소스 파일에만 존재, 클래스 파일에는 존재하지 않음 |
CLASS | 클래스 파일에 존재, 런타임 시점에는 사용 불가. (default) |
RUNTIME | 클래스 파일에 존재, 런타임 시점에 사용 가능 |
선언부
각 유지정책 별 특징
SOURCE
'@Override', '@SuppressWarning' 같은 앹노테이션들 처럼 컴파일러가 사용하는 애노테이션은 유지 정책이 SOURCE이다. 컴파일러를 직접 작성할 것이 아니라면 이 유지정책은 필요 없다고 한다.
CLASS(default)
컴파일러가 애노테이션의 정보를 클래스 파일에 저장될 수 있게 하는 정책이다. 그런데 RUNTIME 유지정책도 클래스 파일에 똑같이 애노테이션 정보가 클래스 파일에 저장되고 런타임 시점에 사용 여부에 따라서 달라진다고 한다.
왜 그럴까?
유지정책이 CLASS일 경우에 클래스 파일을 JVM에 로딩될 때에는 이 CLASS 정책에 해당되는 애노테이션들은 무시되어 JVM 메모리에는 없다. 즉, 프로그램이 실행된 시점에는 이 애노테이션에 대한 데이터를 활용하고 싶어도 이 애노테이션에 대한 데이터가 메모리에 없기 때문에 활용할 수 없는 정책인 것이다.
RUNTIME
애노테이션을 런타임시에도 사용할 수 있는 정책. JVM이 이 애노테이션에 대한 정보를 읽어 메모리에 담기 때문에 이 정책이 적용된 애노테이션은 프로그램이 종료될 때까지 메모리로 남게된다.
또한 런타임 시점에 '리플렉션'이라는 기술을 이용하여 클래스 파일에 저장된 애노테이션의 정보를 읽어서 처리할 수 있다고 한다.
애노테이션에 대한 정보가 javadoc으로 작성한 문서에 포함되도록 한다.
자바에서 제공하는 기본 애노테이션 중에 '@Override'와 '@SupressWarnings'를 제외하고 모두 이 애노테이션이 붙어 있다.
다음은 PracticeAnntation 이라는 커스텀 애노테이션에 @Documented 를 넣어서 javadoc으로 문서화 해보려고한다.
PracticeAnntation에 @Documented 메타 애노테이션을 넣었다
PracticeAnntation을 사용하는 AnnotationClient 클래스에 적용
문서화를 위한 @Documented 애노테이션을 넣어주었고 이제 javadoc을 생성해보자. Intellij IDE가 간편하게 javadoc을 생성해주는 기능이 있다. 다음과 같은 절차로 진행해보자.
- shift 키를 2번 더블 터치
- 검색란에 'generate JavaDoc'을 검색하고 실행한다.
- 새로 올라온 Generate JavaDoc 팝업창에서 한글 문자를 표기하기 위한 option을 추가적으로 다음과 같은 내용을 넣어주어야 한다.
- Other command line arguments 항목에
-encoding UTF-8 -charset UTF-8 -docencoding UTF-8
이 문자열을 넣어준다.- javadoc이 생성될 Output Directory 지정. 이 경로 아래에 javadoc이 저장된다.
위 과정을 완료하고나면 다음과 같이 javadoc 문서가 생성되고 확인할 수 있다.
내용을 보면 내가 정의한 PracticeAnntation에 대한 정보가 문서화 된 것을 볼 수 있다.
예시
장점
컴파일 시점에 조작하기 때문에 런타임 비용이 제로
단점
public한 api가 없다.