Annotation
주석처럼 프로래밍 언어에 영향을 미치지 않으며, 유용한 정보를 제공하는 메모다.
프로그램의 소스코드 안에 다른 프로그램을 위한 정보를 미리 약속된 형식으로 포함시킨다.
▷ 예시
@Test // 이 메서드가 테스트 대상임을 테스트 프로그램에게 알린다.
public void method(){
...
}
▷ 표준 애너테이션
자바에서 기본적으로 제공하는 표준 에너테이션
에너테이션 | 설명 |
@Override | 컴파일러에게 메서드를 오버라이딩하는 것이라고 알린다. |
@Deprecated | 앞으로 사용하지 않을 것을 권장하는 대상에 붙인다. |
@SuppressWarnings | 컴파일러의 특정 경고메세지가 나타나지 않게 해준다. |
@SafeVarags | 지네릭스 타입의 가변인자에게 사용한다. (JDK 1.7) |
@FuncionallInterface | 함수형 인터페이스라는것을 알린다. (JDK 1.8) |
@Native | native메서드에서 참조되는 상수 앞에 붙인다. (JDK 1.8) |
@Target* | 에너테이션이 적용가능한 대상을 지정하는데 사용한다. |
@Documented* | 애너테이션 정보가 javadoc으로 작성된 문서에 포함되게 한다. |
@Inherited* | 에너테이션이 자손 클래스에 상속되도록 한다. |
@Retention* | 에너테이션이 유지되는 범위를 지정하는데 사용한다. |
@Repeatable* | 애너테이션을 반복해서 적용할 수 있게 한다. (JDK 1.8) |
▷ @Override
- 오버라이딩을 오바르게 했는지 컴파일러가 체크하게한다.
- 오버라이딩 할 때 메서드 이름을 잘못 적는 실수를 하는 경우를 예방한다.
class Parent{
void parentMethod();
}
class Child extends Parent{
@Override
void parentmethod(); // 메서드 이름을 잘못 적음
}
▷ @Deprecated
앞으로 사용하지 않을 것을 권장하는 필드나 메서드에 붙인다.
@Deprecated
public int getDate() {
return normalize().getDateOfMonth();
}
▷ @FunctionalInterface
- 함수형 인터페이스에 붙이면, 컴파일러가 올바르게 작성했는지 체크한다.
- 함수형 인터페이스에는 하나의 추상메서드만 가져야 한다는 제약이 있다.
@FuncionalInterface
public interface Runnable {
public abstract void run(); //추상 메서드
}
▷ @SuppressWarnings
- 컴파일러의 경고메세지가 나타나지 않게 억제한다.
- 괄호 안에 억제하고자 하는 경고의 종류를 문자열로 지정한다.
@SuppressWarnings("unchecked") // 지네릭스와 관련된 경고를 억제한다.
ArrayList list = new ArrayList(); // 지네릭 타입을 지정하지 않는다.
list.add(obj); // 여기서 경고가 발생한다.
// 둘이상의 경고를 동시에 억제하려면 다음과 같이 한다.
@SuppressWarnings({"deprecation", "unchecked", "varargs"})
▷ 메타 에너테이션
- 메타 에너테이션은 에너테이션을 위한 에너테이션이다.
- java.lang.annotaion 패키지에 포함되어있다.
애너테이션 | 설명 |
@Target | 애너테이션이 적용가능한 대상을 지정하는데 사용한다. |
@Documented | 애너테이션 정보가 javadoc으로 작성된 문서에 포함되게 한다. |
@Inherited | 애너테이션이 자손 클래스에 상속되도록 한다. |
@Retention | 에너테이션이 유지되는 범위를 지정하는데 사용한다. |
@Repeatable | 애너테이션을 반복해서 적용할 수 있게한다. (JDK1.8) |
▷ @Target
에너테이션을 정의할 때, 적용대상 지정에 사용한다.
@Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE})
@Retention(RetentionPolicy.SOURCE)
public @interface SuppressWarnings {
String[] value();
}
@Target으로 지정할 수 있는 에너테이션의 종류
대상 타입 | 의미 |
ANNOTATION_TYPE | 에너테이션 |
CONSTRUCTOR | 생성자 |
FIELD | 필드(맴버변수, enum상수) |
LOCAL_VARIABLE | 지역변수 |
METHOD | 메서드 |
PACKAGE | 패키지 |
PARAMETER | 매개변수 |
TYPE | 타입(클래스, 인터페이스, enum) |
TYPE_PARAMETER | 타입 매개변수(JDK 1.8) |
TYPE_USE | 타입이 사용되는 모든 곳(JDK 1.8) |
▷ @Retetion
애너테이션이 유지되는 기간을 지정하는데 사용한다.
유지 정책 | 의미 |
SOURCE | 소스 파일에만 존재, 클래스파일에는 존재하지 않음. |
CLASS | 클래스 파일에 존재. 실행시에 사용불가. 기본값 |
RUNTIME | 클래스 파일에 존재. 실행시에 사용가능 |
컴파일러에 의해 사용되는 애너테이션의 유지 정책은 SOURCE다.
@Targe(ElementType.METHOD)
@Retention(RetentionPolicy.SOURCE)
public @interface Override {}
실행시에 사용 가능한 애너테이션 정책은 RUNTIME이다.
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface FunctionalInterface {}
▷ @Documented, @Inherited
javadoc으로 작성한 문서에 포함시키려면 @Documented를 붙인다.
@Doucumentd
@Retedtion(RetentionPolicy.RUNTIME)
@Targer(ElementType.TYPE)
public @interface FuncinalInterface {}
애너테이션을 자손 클래스에 상속하고자 할 때, @Inherited를 붙인다.
@Inherited
@interface SuperAnno {}
@SuperAnno
class Parent {}
class Child extends Parent {}
▷ @Repeatable
반복해서 붙일 수 있는 애너테이션을 정의할 때 사용한다.
@Repeatable(ToDos.class)
@interface ToDo {
String value();
}
@Repeatble이 붙은 애너테이션은 반복해서 붙일 수 있다.
@ToDo("delete test codes.")
@ToDo("override inherited methods")
class MyClass{
...
}
@Repeatable인 @ToDo를 하나로 묶을 컨테이너 에너테이션도 정의해야 한다.
@interface ToDos {
ToDo[] value();
}
▷ 애너테이션 타입 정의하기
애너테이션을 직업 만들어 사용할 수 있다.
@interface 애너테이션 이름{
타입 요소이름();
...
}
애너테이션의 메서드는 추상 메서드이며, 애너테이션을 적용할 때 지정한다. (순서X)
@interface TestInfo {
int count();
String testedBy();
String[] testTools();
TestType testType();
DateTime testDate();
}
@interface DateTime{
String yymmdd();
String hhmmss();
}
▷ 애너테이션의 요소
애너테이션 내에 선언된 메서드를 '에너테이션의 요소' 라고 한다.
아래에 선언된 TestInfo애너테이션은 다섯개의 요소를 갖는다.
@interface TestInfo{
int count();
String testedBy();
String[] testTools();
TestType testType(); // enum TestType { FIRST, FINAL}
DateTime testDate(); // 자신이 아닌 다른 애너테이션을 포함 할 수 있다.
}
@interface DateTime{
String yymmdd();
String hhmmss();
}
애너테이션의 요소는 반환값이 있고 매개변수는 없는 추상 메서드의 형태를 가지며, 상속을 통해 구현하지 않아도 된다.
다만, 애너테이션을 적용할 때 이 요소들의 값을 빠짐없이 지정해주어야 한다.
@TestInfo(
count = 3, testedBy = "KIM",
testTools = {"JUnit", "AutoTester"},
testType = TestType.FIRST,
testDate = @DateTime(yymmdd = "160101", hhmmss = "235959")
)
public class NewClass{
...
}
애너테이션의 각 요소는 기본값을 가질 수 있으며, 기본값이 있는 요소는 애너테이션을 적용 할 때 값을 지정하지 않으면 기본값이 사용된다.
@interface TestInfo{
int count() default 1; //기본값을 1로 지정
}
@TestInfo // @TestInfo(count=1)과 동일
public class NewClass {
...
}
애너테이션 요소가 오직 하나뿐이고 이름이 value인 경우, 애너테이션을 적용 할 때 요소의 이름을 생략하고 값만 적어도 된다.
@interface TestInfo{
String value();
}
@TestINfo("passed")
class NewClass {
...
}
요소의 타입이 배열인 경우, 괄호{}를 사용해서 여러 개의 값을 지정 할 수 있다.
@Test(testTools = {"JUnit", "AutoTester"}) //값이 여러개인 경우
@Test(testTools = "JUnit") //값이 하나일 때는 괄호{} 생략 가능
@Test(testTools={}) //값이 없을 때는 괄호{}가 반드시 필요
기본값을 지정 할 때도 마찬가지로 괄호{}를 사용할 수 있다.
@interface TestInfo{
String[] info() default {"aaa", "bbb"}; //기본값이 여러 개인 경우, 괄호{} 사용
String[] info2() default "ccc"; //기본값이 하나인 경우, 괄호 생략 가능
}
@TestInfo // @TestInfo(info = {"aaa", "bbb"}, info2 = "ccc") 와 동일
@TestInfo(info2={}) // @TestInfo(info = {"aaa", "bbb"}, info2 = {}) 와 동일
class NewClass { ... }
요소의 타입이 배열일 때도 요소의 이름이 value이면, 요소의 이름을 생략할 수 있다. 예를 들어, @SuppressWarnings의 경우, 요소의 타입이 String배열이고 이름이 value이다.
@interface SuppressWarnings {
String[] value();
}
그래서 애너테이션을 적용 할 때 요소의 이름을 생략 할 수 있는 것이다.
//@SuppressWarnings (value={"deprecation", "unchecked"})
@SuppressWarnings ({"deprecation", "unchecked"})
class NewClass{
...
}
▷ 모든 애너테이션의 조상
모든 애너테이션의 조상은 Annotation이다.
그러나 애너테이션은 상속이 허용되지 않으므로 아래와 같이 명시적으로 Annotation을 조상으로 지정할 수 없다.
@interface TestInfo extends Annotations { // ERROR. 허용 되지 않는 표현.
int count();
String testedBy();
}
Annotation은 아래와 같이 일반적인 인터페이스로 정의되어 있다.
package java.lang.annotation;
public interface Annotation{ // Annotation 자신은 인터페이스다.
boolean equals(Object obj);
int hashCode();
String toString();
Class<? extends Annotations> annotationType(); // 애너테이션의 타입을 반환
}
모든 애너테이션의 조상인 Annotation 인터페이스가 위와 같이 정의 되어 있기 때문에, 모든 애너테이션 객체에 대해 equals(), hashCode(), toString()과 같은 메서드를 호출하는 것이 가능하다.
▷ 마커 애너테이션
값을 지정할 필요가 없는 경우, 에너테이션의 요소를 하나도 정의하지 않을 수 있다.
Serializable이나 Cloneable 인터페이스 처럼 요소가 하나도 정의되지 않은 애너테이션을 마커 애너케이션이라 한다.
@Targer(ElementType.METHOD)
@Retention(RetentionPolicy.SOURCE)
public @interface Override {} // 마커 에너테이션. 정의된 요소가 하나도 없다.
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.SOURCE)
public @interface Test {} // 마커 애너테이션. 정의된 요소가 하나도 없다.
▷ 애너테이션 요소의 규칙
- 요소의 타입은 기본형, String, enum, 애너테이션, Class만 허용된다.
- () 안에 매개변수를 선언할 수 없다.
- 예외를 선언할 수 없다.
- 요소를 타입 매개변수로 정의 할 수 없다.
다음 코드에서 무엇이 잘못되었는지 찾아보자.
@interface AnnoTest{
int id = 100; //OK, 상수 선언, static fianl int id = 100;
String major(int i, int j); //에러, 매개변수를 선언할 수 없음
String major() throws Exception; //에러, 예외를 선언할 수 없음
ArrayList<T> list(); //에러, 요소의 타입에 매개변수 사용 불가
}
'JAVA' 카테고리의 다른 글
[Java] Coding Test (Pick two and add them) (0) | 2022.08.08 |
---|---|
[Java] Coding Test (Lotto) (0) | 2022.08.04 |
[Java] enum(열거형) (0) | 2022.08.03 |
[Java] Generic Programming (0) | 2022.08.01 |
[Java] WildCard (0) | 2022.08.01 |