반응형
어노테이션(Annotation)
- 주석처럼 프로그래밍 언어에 영향을 미치지 않으며, 유용한 정보를 제공
@Test // 이 메소드가 테스트 대상임을 테스트 프로그램에게 알림 !
public void method() {
...
}
표준 어노테이션
- Java 에서 제공하는 어노테이션
@Override
- 오버라이딩을 올바르게 했는지 컴파일러가 체크하게 함
- 오버라이딩할 때 메소드 이름을 잘못 적는 실수 등 발생 가능
class Parent {
void parentMethod() {}
}
class Child extends Parent {
void parentmethod() {}
}
오버라이딩 하려고 했으나 실수로 이름 잘못 적었을 때 !
class Child extends Parent {
@Override
void parentmethod() {}
}
어노테이션을 붙여주면 컴파일 시에 오버라이딩이 정상적으로 됐는지 체크할 수 있다 !
@Deprecated
- 앞으로 사용하지 않을 것을 권장하는 필드나 메소드에 붙임
- 예시 :
Date
클래스의getDate()
하위호환성을 보장하기 때문에 사용은 가능하지만 새로운 것을 사용하라고 권장할 때 사용 !
@Deprecated
public int getDate() { ... }
// Calendar.get(...) 으로 변경되었음 !
- @Deprecated 가 붙은 코드를 컴파일하면 경고 메시지 뜨게 설정할 수 있음
- -Xlint 옵션
@SuppressWarnings
- 컴파일러의 경고메시지가 나타나지 않게 억제
- 괄호 안에 억제하고자 하는 경고의 종류를 문자열로 지정
@SuppressWarnings("unchecked") // 리스트에 들어가는 타입 명시하지 않은 경고를 나타나지 않게함
ArrayList list = new ArrayList();
list.add(obj);
// 둘 이상의 경고를 동시에 억제하려면
@SuppressWarnings({"deprecation", "unchecked", "varargs"})
@SafeVarargs
- 가변인자 매개변수를 사용하려고 할 때 발생하는 경고 무시
- 생성자 또는
static
이나final
이 붙은 메소드에만 붙일 수 있음- 오버라이딩이 가능한 메소드에 사용불가
@SafeVarargs
에 의한 경고의 억제를 위해@SuppressWarnings
사용
@SafeVarargs
@SuppressWarnings("varargs")
public static <T> List<T> asList(T ... a) {
return new ArrayList<>(a);
}
@FunctionallInterface
- 함수형 인터페이스에 붙이면 컴파일러가 올바르게 작성했는지 확인
- 함수형 인터페이스는 하나의 추상 메소드만 가져야 한다는 제약이 있음
@FunctionallInterface
public interface Runnable {
public abstract void run(); // 추상 메소드
}
메타 어노테이션
- 어노테이션을 만들 때 사용하는 어노테이션
- java.lang.annotation 패키지에 포함
@Target
- 어노테이션을 적용할 수 있는 대상의 지정에 사용
@Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE})
@Retension(RetentionPolicy.SOURCE)
public @interface SuppressWarnings {
String[] value();
}
어노테이션을 어디에 붙일 수 있는지 지정할 수 있음
@Retension
- 어노테이션이 유지 되는 기간을 지정
SOURCE // 소스 파일에만 존재. 클래스 파일에는 존재하지 않음
CLASS // 클래스 파일에 존재. 실행 시에 사용불가. 기본값
RUNTIME // 클래스 파일에 존재. 실행 시에 사용가능
- 컴파일러에 의해 사용되는 어노테이션의 유지 정책은
SOURCE
@Target(ElementType.METHOD)
@Retension(RetentionPolicy.SOURCE)
public @interface Override {}
- 실행 시에 사용 가능한 어노테이션의 정책은
RUNTIME
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface FunctionalInterface {}
@Documented, @Inherited
javadoc
으로 작성한 문서에 포함시키려면@Documented
를 붙임
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface FunctionalInterface {}
- 어노테이션을 자손 클래스에 상속하고자 할 때,
@Inherited
를 붙임
@Inherited
@interface SupperAnno {}
@SupperAnno
class Parent {}
class Child extends Parent {}
@Repeatable
- 반복해서 붙일 수 있는 어노테이션을 정의할 때 사용
@Repeatable(ToDos.class)
@interface ToDo {
String value();
}
@ToDo("delete test codes.")
@ToDo("override inherited methods")
class MyClass { ... }
어노테이션 타입 정의
- 직접 만들어서 사용 가능
@interface 어노테이션이름 {
타입 요소이름();
...
}
- 어노테이션의 메소드는 추상 메소드
- 어노테이션을 적용할 때는 순서 상관없이 모두 지정해야 함
@interface TestInfo {
int count();
String testedBy();
String[] testTools();
TestType testType(); // enum TestType { FIRST, FINAL }
DateTime testDate(); // 자신이 아닌 다른 어노테이션 포함 가능 (아래의 @DateTime)
}
@interface DateTime {
String yymmdd();
String hhmmss();
}
@TestInfo(count=3, testBy="kim", ...) // 이런 식으로 모두 지정해줘야 함 !
class Test { ... }
어노테이션 요소
- 기본적으로 사용될 수 있는 값 지정 가능 (null 제외)
@interface TestAnno {
int value() default 1;
}
@TestAnno // value 지정하지 않아도 됨 -> 1
public class TestClass {}
- 요소 이름이 value 이고 요소가 하나일 때는 이름 생략가능
@TestAnno(10) // value = 10 이 들어감
public class TestClass {}
- 요소의 타입이 배열인 경우, 중괄호를 사용해서 값 지정
@interface TestArrayAnno {
int[] num() default { 0, 1, 2, 3, 4 };
int[] numZero() default 0; // 배열의 요소가 하나면 중괄호 생략 가능
}
@TestArrayAnno // num[] = { 0, 1, 2, 3, 4 }, numZero[] = { 0 }
@TestArrayAnno(numZero = {}) // num[] = { 0, 1, 2, 3, 4 }, numZero[] = { }
모든 어노테이션의 조상 java.lang.annotation.Annotation
- Annotation 은 모든 어노테이션의 조상이지만 상속은 불가
@interface TestInfo extends Annotation { // 에러 ! 허용되지 않는 표현
int count();
String testedBy();
...
}
- 사실 Annotation 은 인터페이스로 정의되어 있음
package java.lang.annotation;
public interface Annotation { // Annotation 자신은 인터페이스 !
boolean equals(Object obj);
int hashCode();
String toString();
Class<? extends Annotation> annotationType(); // 어노테이션 타입 반환
Annotation 인터페이스 안의 메소드들은 추상 메소드이지만,
컴파일러가 자동으로 내용을 구현해주기 때문에 메소드 사용 가능.
모든 어노테이션의 조상이므로 기존 어노테이션이든, 새로 정의한 어노테이션이든 이 내용이 다 포함되어 있다.
마커 어노테이션 - Marker Annotation
- 요소가 하나도 정의되지 않은 어노테이션
@Target(ElementType.METHOD)
@Retension(RetentionPolicy.SOURCE)
public @interface Override {} // 요소가 0개
@Target(ElementType.METHOD)
@Retension(RetentionPolicy.SOURCE)
public @interface Test {} // 요소가 0개
안에 요소 없이 어노테이션이 붙어있는 것만으로도 정보 제공 가능.
어노테이션 요소의 규칙
- 어노테이션의 요소를 선언할 때 아래의 규칙을 반드시 지켜야 함
- 요소의 타입은 기본형, String, enum, 어노테이션, Class 만 허용
- 괄호 안에 매개변수를 선언할 수 없음
- 예외를 선언할 수 없음
- 요소를 타입 매개변수로 정의할 수 없음
아래 코드에서 문제를 살펴보자 !
@interface AnnoTest {
int id = 100; // OK. 상수 들어갈 수 있음
String major(int i, int j); // 에러. 매개변수 들어갈 수 없음
String minor() throws Exception; // 에러. 예외처리 불가
ArrayList<T> list(); // 에러. 타입 매개변수 정의 불가
}
- 상수 가능하고, 추상메소드로 만들어야 함 !
728x90
반응형