ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • Java 항해일지 - 12. 애노테이션
    공부일기/자바 스터디 2021. 2. 2. 23:43

    목표

    자바의 애노테이션에 대해 학습하세요.

    학습할 것 (필수)

    • 애노테이션 정의하는 방법
    • @retention
    • @target
    • @documented
    • 애노테이션 프로세서

    애너테이션이란?

     

    애너테이션은 프로그램의 소스코드 안에 다른 프로그램을 위한 정보를 미리 약속된 형식으로 포함시킨 것이다. 주석처럼 프로그래밍 언어에 영향을 미치지 않으면서 다른 프로그램에게 유용한 정보를 제공할 수 있다는 장점을 지녔다. 

    예를 들어 작성한 소스코드 중에 특정 메서드만 테스트하기를 원할 경우, 아래와 같이 '@Test'라는 애너테이션을 메서드 앞에 붙인다. '@Test'는 '이 메서드를 테스트해야 한다'는 것을 테스트 프로그램에게 알리는 역할만 하고, 메서드가 포함된 프로그램 자체에는 아무런 영향을 미치지 않는다. 위에서 설명했듯 주석처럼 존재하지 않는 것이나 다름 없는 것이다.

     

    @Test        // 이 메서드가 테스트 대상임을 테스트 프로그램에게 알린다.
    public void method() {
                    ...
    }

     

    애너테이션은 JDK에서 기본적으로 제공하는 것과 다른 프로그램에서 제공하는 것들이 있다. 애너테이션이 제공한 정보를 이용해서 내부적으로 어떻게 처리하는 지 공부하기 보단 JDK에서 제공하는 표준 애너테이션은 주로 컴파일러에게 유용한 정보를 제공한다는 점까지만 알아두자!

     

     

    애너테이션에는 위에서 설명한 애너테이션과 애너테이션을 정의하는데 사용되는 애너테이션의 애너테이션인 '메타 애너테이션'이 있다. 

     

     

    아래는 자바에서 기본적으로 제공하는 애너테이션에 대한 표이다.

    애너테이션 설명
    @Override 컴파일러에게 메서드를 오버라이딩하는 것이라고 알린다.
    @Deprecated 앞으로 사용하지 않을 것을 권장하는 대상에 붙인다.
    @SuppressWarnings 컴파일러의 특정 경고메시지가 나타나지 않게 해준다.
    @SafeVarargs 지네릭스 타입의 가변인자에 사용한다. (JDK 1.7부터 사용)
    @FunctionalInterface 함수형 인터페이스라는 것을 알린다(JDK 1.8부터 사용)
    @Native native 메서드에서 참조되는 상수 앞에 붙인다. (JDK 1.8)

    자바에서 기본적으로 제공하는 표준애너테이션들(메타 애너테이션은 밑에서 다룬다.)

     

     

    @Override

    메서드 앞에만 붙일 수 있는 애너테이션으로 조상의 메서드를 오버라이딩한다는 것을 컴파일러에게 알려준다.

    예를들어 어떤 클래스를 상속받아 새로운 클래스를 만들고, 조상 메서드를 정의할 때, 아래 예시처럼 이름을 잘못 써도 컴파일러는 조상 메서드에 대한 오버라이딩이 잘못 됐는지 판단할 수 없다. 단지 새로운 메서드로 인식할 뿐인데, 만약 @Override를 붙여 해당 메서드가 조상 메서드를 오버라이딩 하는 것을 컴파일러에게 알려주게 되면, 만약 조상 메서드에 작성하려는 메서드의 이름과 같은 메서드가 없다면 에러메시지를 출력한다.

     

    package WhiteshipStudy;
    
    public class Annotation {
        void parentMethod(){
        }
    }

    위와 같은 조상 클래스가 있고, 아래에서 조상 메서드를 오버라이딩 해보자.

     

    이름이 다른 경우 컴파일 에러가 나타나고 있다.
    조상 메서드와 이름을 같게 하자 컴파일 에러가 나지 않는다.

    오버라이딩할 때 메서드 앞에 '@Override'를 붙이는 것이 필수는 아니다. 그러나 알아내기 어려운 실수를 미연에 방지할 수 있으므로 오버라이딩할 땐 반드시 애너테이션을 사용하자.

     

     

    @Deprecated

    새로운 버전의 JDK가 나올 때 새로운 기능이 추가되거나 기존의 부족했던 기능들이 개선을 하기도 한다. 이 과정에서 기존의 기능을 대체할 것들이 추가되어도, 이미 여러 곳에서 사용되고 있을지 모르는 기존의 것들을 삭제할 수는 없다(하위 호환성).

     

    그래서 생각해낸 방법이 더 이상 사용되지 않는 필드나 메서드에 '@Deprecated'를 붙이는 것이다. 이 애너테이션이 붙은 대상은 다른 것으로 대체되었으니 더 이상 사용하지 않을 것을 권한다는 의미이다. 10주차 멀티스레드 프로그래밍 스터디에서 교착상태를 막기 위해 '@Deprecated'가 붙은 메서드에 대해 알아봤었다. (young-bin.tistory.com/76-스레드의 실행제어 부분)

     

     

     

    @FunctionalIterface

    함수형 인터페이스를 선언할 때, 이 애너테이션을 붙이면 컴파일러가 함수형 인터페이스를 올바르게 선언했는지 확인하고, 잘못된 경우 에러를 발생시킨다. 필수는 아니지만 실수 방지를 위해 함수형 인터페이스 선언 시 반드시 붙이자.

    @FunctionalInterface
    public interface Runnable {
        public abstract void run(); // 추상메서드
    }

     

     

    @SuppressWarnigns

    컴파일러가 보여주는 경고메시지가 나타나지 않게 억제해준다. 

    그런데 컴파일러가 보여주는 경고메시지를 억제하는 경우가 언제 필요할까에 대한 의문이 생겼다. 이 부분은 추가로 공부해나가며 수정해야겠다.

     

     

     

    애너테이션 정의하는 방법

    애너테이션을 정의하는 방법은 인터페이스를 정의하는 것과 같으나 '@' 기호를 앞에 붙여주면 된다.

    public @interface AnnotationName() {
            타입 요소이름(); // 애너테이션의 요소를 선언한다.
    }

     

     

    메타 애너테이션

    애너테이션 설명
    @Target 애너테이션이 적용가능한 대상을 지정하는데 사용한다.
    @Documented 애너테이션 정보가 javadoc으로 작성된 문서에 포함되게 한다.
    @Inherited 애너테이션이 자손 클래스에 상속되도록 한다.
    @Retention 애너테이션이 유지되는 범위를 지정하는데 사용한다.
    @Repeatable 애너테이션을 반복해서 적용할 수 있게 한다. (JDK 1.8)

     

     

    @Target

    애너테이션이 적용가능한 대상을 지정하는데 사용한다. 지정할 수 있는 애너테이션 적용대상의 종류는 다음과 같다.

    대상 타입 의미
    ANNOTATION_TYPE 애너테이션
    CONSTRUCTOR 생성자
    FIELD 필드(멤버변수, enum 상수)
    LOCAL_VARIABLE 지역변수
    METHOD 메서드
    PACKAGE 패키지
    PARAMETER 매개변수
    TYPE 타입(클래스, 인터페이스, enum)
    TYPE_PARAMETER 타입 매개변수(JDK 1.8)
    TYPE_USE 타입이 사용되는 모든 곳(JDK 1.8)

     

     

     

    @Retention

    애너테이션이 유지되는 기간을 지정하는데 사용된다. 애너테이션 유지 정책의 종류를 표로 나타내보자.

    유지 정책 의미
    SOURCE 소스 파일에만 존재, 클래스파일에는 존재하지 않음.
    CLASS 클래스 파일에 존재, 실행시 사용 불가, 기본값
    RUNTIME 클래스 파일에 존재, 실행시 사용 가능.

    '@Override'나 '@SuppressWarnings'처럼 컴파일러가 사용하는 애너테이션은 유지 정책이 'SOURCE'이다.

    'CLASS' 유지 정책은 컴파일러가 애너테이션의 정보를 클래스 파일에 저장할 수 있게는 하지만, 클래스 파일이 JVM에 로딩될 때 애너테이션의 정보가 무시되기 때문에, 실행시 애너테이션에 대한 정보를 얻을 수 없다.

    'RUNTIME'유지 정책을 사용하게 되면, 실행시 '리플렉션'을 통해 클래스 파일에 저장된 애너테이션의 정보를 읽어서 처리할 수 있다. '@FunctionalInterface'는 컴파일러가 체크해주는 애너테이션이지만, 실행 시에도 사용되므로 유지정책이 'RUNTIME'이다.

     

     

    @documented

    애너테이션에 대한 정보가 javadoc으로 작성한 문서에 포함되도록 한다. 자바에서 제공하는 기본 애너테이션 중 '@Override'와 '@SuppressWarnings'를 제외하고는 모두 이 메타 애너테이션이 붙어있다.

     

     

     

    애노테이션 프로세서

    런타임시에 리플랙션을 사용하는 어노테이션과는 달리 컴파일 타임에 이루어진다.

    컴파일 타임에 어노테이션들을 프로세싱하는 javac에 속한 빌드 툴로 어노테이션의 소스코드를 분석하고 처리하기 위해 사용되는 훅이다.

    보일러플레이트 코드를 제거하는데 도움이 된다. 
    ( AbstractProcessor를 implements하여 구현체를 만들 수 있으며 Lombok의 @Getter, @Setter와 같은 어노테이션을 이용하는 것만으로도 컴파일 타임에 알아서 getter/setter를 만들어주는 방식으로 보일러플레이트 코드 제거 )

Designed by Tistory.