본문 바로가기

자바의 정석 정리

자바의 정석 - 12.3 애너테이션(annotation)

12.3.1 애너테이션이란?

  • 프로그램의 소스코드 안에서 다른 프로그램을 위한 정보를 미리 약속된 형식으로 포함시킨 것
  • 프로그램 자체에는 아무런 영향일 끼치지 않음
  • @Test // 이 메서드가 테스트 대상임을 테스트 프로그램에게 알림 public void method(){...}
  • 해당 프로그램에 미리 정의된 종류와 형식으로 작성해야 의미가 있음
  • JDK에서 제공하는 표준 애너테이션은 주로 컴파일러를 위한 것임

12.3.2 표준 애너테이션 종류

  • @Override
    • 메서드 앞에만 붙일 수 있음
    • 조상의 메서드를 오버라이딩하는 것이라는걸 컴파일러에게 알리는 역할을 함
    • @Override void parentmethod()
  • @Deprecated
    • 더 이상 사용하지 않는 것을 권장한다는 의미임
    • @Deprecated int oldField
  • @SuppressWarnings
    • 경고 메시지가 나타나지 않게 억제함
    • 묵인해야 하는 경고가 발생하는 경우 붙이면 됨
    • ```java
      /*
      @SuppressWarnings("deprecation") : @Deprecated가 붙은 대상을 사용해서 발생하는 경고 억제
      @SuppressWarnings("unchecked") : 지네릭스를 사용하지 않아서 생하는 경고 억제
      @SuppressWarnings("varags") : 가변인자의 타입이 지네릭 타입일 때 발생하는 경고 억제
    • /// 중복 가능
      @SuppressWarnings({"uncheked", "varags"})
    • @SuppressWarnings("uncheked") // 지네릭스와 관련된 경고를 억제
      ArrayList list = new ArrayList(); // 지네릭 타입을 지정하지 않음
      list.add(obj)
  • @SafeVarargs
    • 메서드에 선언된 가변인자의 타입이 non-reifiable 타입일 경우 발생
    • static이나 final이 붙은 메서드와 생성자에만 붙일 수 있음
    • @SafeVarargs // unchecked 경고 억제 @SuppressWarnings("varags") // varags 경고 억제 public static <T> List<T> asList(T... a){ return new ArrayList<>(a); }
  • @FunctionalInterface
    • 함수형 인터페이스를 선언할 때, 올바르게 선언했는지 확인함
    • 올바르게 선언하지 않은 경우 에러를 발생시킴
    • @FunctionalInterface public interface Runnable{ publlic abstract void run(); // 추상 메서드 }
  • @Native
    • 상수 필드에 붙이는 애너테이션임
    • 네이티브 메서드는 JVM이 설치된 OS의 메서드를 말함
    • 보통 C언어로 작성되어 있는데, 자바에서는 메서드의 선언부만 정의하고 구현하지 않음
    • 단, JNI(Java Native Interface)를 이용하여 자바에 정의된 네이티브 메서드와 OS의 메서드를 연결하는 작업을 하고 있음
    • @Native public static final long MIN_VALUE = 0x8000000000000000L; // 최상위 클래스의 Object의 메서드 일부는 native임 public class Object{ private static native void registerNatives(); // 네이티브 메서드 static { registerNatives(); } protected native Object clone() throws CloneNotSupportedException; public final native Class<?> getClass(); public final native void notify(); public final native void notifyAll(); public final native void wait(long timeout) throws InterruptedException; public final native int hashCode(); ... }
  • @Target*
    • 애너테이션이 적용가능한 대상을 지저하는데 사용됨
    • 종류
      • ANNOTATION_TYPE : 애너테이션
      • CONSTRUCTOR : 생성자
      • FIELD : 필드(인스턴스 변수)
      • LOCAL_VARIABLE : 지역변수
      • METHOD : 메서드
      • PACKAGE : 패키지
      • PARAMETER : 매개변수
      • TYPE : 타입(클래스, 인터페이스, enum)
      • TYPE_PARAMETER : 타입 매개변수(JDK1.8)
      • TYPE_USE : 타입이 사용되는 모든 곳(JDK1.8)
      @Target({FIELD, TYPE})
      public @interface MyAnootation{...}
  • @Documented*
    • 애너테이션에 대한 정보가 javadoc으로 작성한 문서에 포함되도록 함
    • @Documented @Retention(RetentionPolicy.RUNTIME) @Target(ELEMENT.TYPE) public @interface FunctionalInterface{}
  • @Inherited*
    • 조상 클래스에 붙이면 자손 클래스도 이 애너테이션이 붙은 것과 같이 인식됨
    • @Inherited @interface SupperAnno{} @SuperAnno class Parent{} class Child extends Parents {}
  • @Retention*
    • 애너테이션이 유지되는 기간을 정함
    • 종류
      • SOURCE : 소스 파일에만 존재. 클래스 파일에는 존재하지 않음
      • CLASS : 클래스 파일에 존재. 실행시에 사용불가. 기본값
      • RUNTIME : 클래스파일에 존재. 싱행시에 사용가능
      @Documented
      @Retention(RetentionPolicy.RUNTIME) // 런타임
      @Target(ELEMENT.TYPE)
      public @interface FunctionalInterface{}
  • @Repeatable*
    • 애너테이션을 여러 번 붙을 ㅅ ㅜ있음
    • @Repeatable(ToDos.class) @interface Todo{ String value(); } @Todo("AAAA") @Todo("BBBB") // 반복 가능 class MyClass{...}

12.3.3 메타 애너테이션

  • 애너테이션을 위한 애너테이션임
  • 애너테이션의 적용대상(Target)이나 유지기간(Retention)등을 지정하는데 사용됨

12.3.4 애너테이션 타입 정의하기

  • 정의 방법
  • @interface 애너테이션 이름 { 타입 요소이름(); // 애너테이션의 요소를 선언함 ... }
  • 애너테이션의 요수는 반환값이 있고, 매개변수는 없는 추상 메서드의 형태임
  • 요소들을 빠짐없이 지정해야 함
  • @interface TestInfo{ int count(); String testedBy(); ... } @TestInfo(count = 3, testedBy = "Kim", ...) public class NewClass{...}
  • 값을 지정합지 않으면 기본값이 사용됨
  • @interface TEstInfo{ int count() default 1; // 기본값을 1로 지정 ... }
  • 애너테이션의 요소가 오직 하나일 경우, 애너테이션을 적용할 때 요소의 이름 생략 가능
  • @interface TestInfo{ String value(); } @TestInfo("passed") public class NewClass{...}
  • 요소의 타입이 배열인 경우 괄호 사용
  • @interface TestInfo{ String[] value(); } // 값이 여러 개인 경우 @TestInfo(value = {"passed", "TTT"}) public class NewClass{...} // 값이 하나인 경우 @TestInfo(value = "passed") public class NewClass{...}

12.3.5 java.lang.annotation.Annotation

  • 모든 애너테이션의 조상은 Annotation
  • 그러나, 애너테이션은 상속이 허용되지 않으므로 명시적으로 조상을 지정할 수 없음
  • @interface TestInfo extends Annotation {...} // 에러
  • Annotation은 애너테이션이 아닌 일반적인 인터페이스로 정의되어 있음
  • package java.lang.annotation; public interface Annotation{ // 일반적인 인터페이스 boolean equals(Object obj); int hashCode(); String toString(); Class<> extends Annotation> annotationType(); // 애너테이션 타입을 반환 }
  • 모든 애너테이션의 조상인 Annotation가 위와 같이 정의 되어있기 때문에, equals()와 같은 메서드를 호출할 수 있음
  • Class<AnnotationTest> cls = AnnotationTest.class; Annotation[] annoArr = AnootationTest.class.getAnnotations(); for(Annotation a : annoArr){ System.out.println("toString()" + a.toString); ... }
  • 요소가 하나도 정의되지 않은 애너테이션을 마커 애너테이션(Marker Annotation)이라 함
  • @Target(ElementType.METHOD) @Retention(RetentionPolicy.SOURCE) public @interface Override{} // 정의된 요소가 없음
  • 애너테이션 요소의 규칙
    1. 요소의 타입은 기본형, String, enum, 애너테이션, Class만 허용됨
    2. ()안에 매개변수를 선언할 수 없음
    3. 예외를 선언할 수 없음
    4. 요소를 타입 매개변수로 정의할 수 없음