자바의 정석 Chapter 12 애너테이션

Eunkyung·2021년 11월 3일
0

Java

목록 보기
13/21

1. 애너테이션

과거에는 소스코드와 문서를 따로 관리하였는데 서로 간의 불일치가 발생하였다. 이를 해결하기 위해 소스코드와 문서를 하나로 합치는 javadoc.exe를 만들었다.
'/**'로 시작하는 주석 안에 소스코드에 대한 설명들이 있고 '@'이 붙은 태그가 있는데 이를 애너테이션이라고 한다. 애너테이션은 주석처럼 프로그래밍 언어에 영향을 미치지 않으면서 유용한 정보를 제공한다.

1.2 표준 애너테이션

컴파일러에게 유용한 정보를 제공한다.

  1. @Override
    오버라이딩하는 메서드라는 것을 알린다. 부모 메서드의 이름을 잘못 적거나 오버라이딩하지 않은 경우 컴파일러가 에러 메시지를 출력한다.
class Child extends Parent {
	@Override
    void parentMethod()
}
  1. @Deprecated
    앞으로 사용하지 않을 것을 권장하는 대상에 붙인다. 하위호환성을 고려하여 기존의 것들을 함부로 삭제하지 않고 @Duprecated를 사용하는데 이를 사용할 경우 컴파일 시 경고 메시지가 출력된다.
class NewClass {
	@Deprecated
    int oldField;
    
    @Deprecated
    int getOldField(){
    	return oldField;
    }
}
  1. @SuppressWarnings
    특정 경고메시지가 나타나지 않게 해준다.
@SuppressWarnings("unchecked")
  1. @FunctionalInterface
    함수형 인터페이스라는 것을 알리는 애너테이션으로 하나의 추상 메서드만 정의한다.
@FunctionalInterface
public interface Runnable {
	public abstract void run();
}

1.3 메타 애너테이션

새로운 애너테이션을 정의할 때 애너테이션의 적용대상이나 유지기간 등을 지정하는데 사용된다.

  1. @Target
    애너테이션이 적용가능한 대상을 지정하는데 사용된다.
@Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VAIABLE})
  1. @Retention
    애너테이션이 유지되는 기간을 지정하는데 사용된다.
  • SOURCE
    소스 파일에만 존재. 클래스 파일에는 존재하지 않음
  • CLASS
    클래스 파일에 존재. 실행시 사용불가. 기본값
  • RUNTIME
    클래스 파일에 존재. 실행시 사용가능
  1. Documented
    애너테이션에 대한 정보가 javadoc으로 작성한 문서에 포함되도록 한다.
  2. @Inherited
    애너테이션이 자식 클래스에 상속되도록 한다.
@Inherited // @SupperAnno가 자식까지 영향 미침
@interface SupperAnno {}

@SuperAnno
class Parent {}

class Child extends Parent {} // Child에 애너테이션이 붙은 것으로 인식
  1. @Repeatable
    애너테이션을 여러 번 붙일 수 있다.

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

@interface 애너테이션이름 {
	타입 요소이름();
}

애너테이션 내에 선언된 메서드를 애너테이션의 요소라고 한다. 요소는 반환값이 있고 매개변수는 없는 추상 메서드의 형태를 가지며 구현하지 않아도 된다.

  • 애너테이션 요소의 규칙
    1. 요소의 타입은 기본형, String, enum, 애너테이션, Class만 허용
    2. ()안에 매개변수 선언불가
    3. 예외 선언불가
    4. 요소를 타입 매개변수<T>로 정의불가

전체 소스코드

package ch12.AnnotationEx5;

import java.lang.annotation.Annotation;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

@Deprecated
@SuppressWarnings("1111") // 유효하지 않은 애너테이션 무시됨
@TestInfo(testedBy = "aaa", testDate = @DateTime(yymmdd = "161601", hhmmss = "235959"))
public class AnnotationEx5 {
    public static void main(String[] args) {
        // AnnotationEx5클래스에 적용된 애너테이션을 실행시간에 얻으려면 AnnotationEx5의 Class 객체를 얻는다.
        // 모든 클래스 파일은 클래스로더에 의해 메모리에 올라갈 때 클래스에 대한 정보가 담긴 객체를 생성하는데 이를 클래스 객체라고 한다.
        Class<AnnotationEx5> cls = AnnotationEx5.class; // 클래스 객체를 의미하는 리터럴
        // 클래스 객체에는 해당 클래스에 대한 모든 정보뿐만 아니라 애너테이션의 정보도 가지고 있다.
        TestInfo anno = (TestInfo) 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();

        // AnnotationEx5에 적용된 모든 애너테이션을 배열로 가져온다.
        Annotation[] annoArr = cls.getAnnotations();

        for (Annotation a : annoArr) {
            System.out.println(a);
        }
    }
}

@Retention(RetentionPolicy.RUNTIME) // 실행 시에 사용가능
@interface TestInfo {
    int count() default 1;

    String testedBy();

    String[] testTools() default "JUnit";

    TestType testType() default TestType.FIRST; // enum TestType {FIRST, FINAL}

    DateTime testDate(); // 자신이 아닌 다른 애너테이션 포함 가능
}

@Retention(RetentionPolicy.RUNTIME)
@interface DateTime {
    String yymmdd();

    String hhmmss();
}

enum TestType {FIRST, FINAL}

출처

  • 자바의 정석 - 남궁성 지음
profile
꾸준히 하자

0개의 댓글