ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [자바의 정석] Ch.12 지네릭스, 열거형, 애너테이션
    스터디플래너/공부하기 2022. 7. 2. 10:05

    3. 애너테이션

    3.1 애너테이션이란?

     애너테이션이란 주석이란 뜻으로, 프로그램의 소스코드 안에서 프로그램에 영향을 미치지 않으면서 프로그램에 유용한 정보를 미리 약속된 형식으로 포함시키는 것이다.

     아래 소스코드에서 '@Test'라는 애터네이션을 붙이면 이 메서드는 테스트해야한다는 것을 테스트 프로그램에게 알려줄 뿐 프로그램에 영향을 미치지 않는다.

    @Test // 이 메서드가 테스트 대상임을 테스트 프로그램(ex. JUnit)에게 알려줌
    public void add(int num1, int num2){
    	return num1 - num2;
    }

     초기 자바 개발자들은 소스코드와 소스코드에 대한 문서를 따로 작성했으나, 소스코드를 수정할 때마다 소스코드에 대한 문서를 함께 수정하는 것이 번거로워지자 소스코드와 문서가 불일치하게 되었다. 소스코드와 문서를 하나의 파일로 합쳤고 문서를 주석으로 달았는데 이것을 javadoc.exe을 이용하여 문서만 따로 추출하면 우리가 아는 java 공식 문서가 된다.

     소스코드와 소스코드에 대한 설정파일인 XML문서로 관리했으나 그 문서를 별도로 관리하는 것이 어려워졌고, 하나로 합치면서 애너테이션이 생겼다.

     

     

    3.2 표준 애너테이션

    - 표준 애너테이션이란 자바에서 제공하는 애너테이션이다.

    @Override

     메서드 앞에만 붙일 수 있는 애너테이션. 조상 메서드를 오버라이딩하는 것을 컴파일러에게 알려주는 역할을 한다. 오버라이딩 할 때 메서드의 이름을 잘못 적는 경우가 많지만 컴파일러는 잘못 적은 메서드를 새로운 메서드로 인식할 뿐 오버라이딩 된 메서드로 인식하지 않는다. 하지만 '@Override'를 붙여 컴파일하면 조상 클래스의 메서드로 해당 메서드가 있는지 확인하고 없다면 에러메세지를 출력한다.

    @Deprecated

      다른 것으로 대체되었으니 더이상 사용하지 않을 것을 권장하는 필드나 메서드에 붙인다. @Deprecated가 붙은 대상을 사용하는 코드를 작성하면 컴파일할 때 메세지가 나타나고, '-Xlint:deprecation'옵션을 사용하여 컴파일하면 자세한 내용을 알 수 있다.

     새로운 버젼의 JDK가 소개될 때 새로운 기능이 추가될 뿐만 아니라 기존에 부족했던 기능들을 개선하기도 한다. 이 과정에서 기존의 기능을 대체할 것들이 추가되어도 Java는 하위호환성을 중요시하므로 이미 사용하고 있을 수 있는 것들을 함부로 삭제하지 않는다. 

    @FunctionalInterface

     컴파일러가 함수형 인터페이스를 잘 작성했는지 확인한다. 함수형 인터페이스에는 하나의 추상메서드만 가져야 한다는 제약이 있다. 함수형 인터페이스는 Chapter14. 람다와 스트림에서 다룬다.

    @SuppressWarnings

     컴파일러에 경고메세지가 나타나지 않게 억제한다. 괄호 안에 억제하고자하는 경고의 종류를 문자열로 지정한다. 둘 이상의 경로메세지를 억제할 때는 괄호 안에 중괄호를 이용하여 배열처럼 나열한다. '-Xlint' 옵션으로 컴파일하면 경고 메세지를 확인할 수 있다. 

    @SafeVarargs

     메서드에 선언된 가변인자의 타입이 non-reifiable타입인 경우, 해당 메서드를 선언하는 부분과 호출하는 부분에서 "unchecked"경고가 발생한다. 해당 코드에 문제가 없다면 이 경고를 억제하기 위해 '@SafeVarargs'를 사용해야 한다.

     static이나 final이 붙은 메서드와 생성자에만 붙일 수 있으므로 오버라이드될 수 있는 메서드에는 사용할 수 없다. non-reifiable타입이란 컴파일 후에 제거되는 타입을 말한다. reifiable타입은 컴파일 후에도 제거되지 않는 타입을 말한다.

     메서드를 선언할 때 @SafeVarargs를 붙이면 이 메서드를 호출하는 곳에서 발생하는 경고도 억제된다. @SafeVarargs대신 @SuppressWarnings("unchecked")로 경고를 억제하려면 메서드를 선언한 곳 뿐만 아니라 메서드를 호출한 곳에서도 애너테이션을 붙여야 한다.

     @SafeVarargs로 'unchecked'경고는 억제할 수 있지만, 'varargs'경고는 억제할 수 없기 때문에 습관적으로 @SafeVarargs와 @SuppressWarnings("varargs")를 같이 붙인다.

     

     

    3.3 메타 애너테이션

    메타 애너테이션이란 애너테이션을 위한 애너테이션이다. 애너테이션을 정의할 때 적용 대상이나 유지기간 등을 지정하는데 사용한다.

    @Target

    애너테이션이 적용가능한 대상을 지정하는데 사용한다. 

    @Documented
     @Retention(value=RUNTIME)
     @Target(value={CONSTRUCTOR,FIELD,LOCAL_VARIABLE,METHOD,PACKAGE,PARAMETER,TYPE})
    public @interface Deprecated

    @Deprecated의 타겟은 CONSTRUCTOR,FIELD,LOCAL_VARIABLE,METHOD,PACKAGE,PARAMETER,TYPE이다. @Target으로 지정할 수 있는 애너테이션의 종류는 아래와 같다.

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

    TYPE은 타입을 선언할 때, TYPE_USE는 해당 타입의 변수를 선언할 때 애너테이션을 붙일 수 있다는 뜻이다. FIELD는 기본형에, TYPE_USE는 참조형에 사용된다.

    @Retention

    애너테이션이 유지되는 기간을 지정하는데 사용한다.

    SOURCE 소스파일에만 존재. 컴파일한 클래스 파일에는 존재 하지 않음
    CLASS ClassLoader가 적용된 클래스 파일에 존재. 실행시에는 사용불가. 기본값. 잘 사용하지 않음
    RUNTIME 클래스 파일에 존재. 실행시 사용 가능

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

    CLASS 유지정책은 컴파일러가 클래스 파일에 애너테이션 정보를 저장할 수 있게 해주지만 클래스파일이 JVM에 로딩될 때는 애너테이션의 정보가 무시되어 실행시에는 애너테이션에서 얻을 수 있는 정보가 없다. 기본값이지만 잘 사용하지 않는 이유이다.

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

    @Documented

    애너테이션에 대한 정보가 javadoc으로 작성한 문서에 포함되도록 한다.

    @Inherited

    애너테이션이 자식 클래스에 상속되게 한다. 조상클래스에 '@Inherited'를 붙이면 자식클래스도 '@Inherited'가 붙은 것으로 인식한다.

    @Repetable

    하나의 대상에 하나의 애너테이션을 붙이는데 '@Repetable'이 붙은 애너테이션은 여러 번 붙일 수 있다. 애너테이션을 선언할 때 해당 애너테이션을 배열타입으로 선언하고 이름을 value로 해줘야 한다.

    @Native

    네이티브 메서드에 의해 참조되는 상수필드에 붙이는 애너테이션이다. 네이티브 메서드란 JVM이 설치된 OS의 메서드를 말한다. 네이티브 메서드는 주로 C언어로 작성되어 있는데 자바에서는 추상메서드처럼 메서드의 선언부만 정의하고 구현하지 않는다.  Object클래스의 메서드들은 대부분 네이티브 메서드이다. 

     

     

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

    애너테이션은 '@' 기호를 붙이는 것을 제외하면 인터페이스를 정의하는 것과 동일하다.

    애너테이션의 요소

    애너테이션 내에 선언된 메소드를 애너테이션의 요소라고 한다. 애너테이션의 요소는 반환값이 있고 매개변수는 없는 추상 메서드의 형태를 갖고 상속을 통해 구현하지 않아도 된다. 애너테이션의 각 요소는 기본값을 가질 수 있다. 애너테이션의 요소가 하나이고, 그 이름이 value인 경우 요소의 이름을 생략하고 값만 적어도 된다. 배열일 때도 이름을 생략할 수 있다. 

    // 애너테이션 정의
    @interafce TestInfo{
    	int count() default 1;
        String testBy();
        String[] testTools();
        TestType testType(); //enum TestType { FIRST, FINAL }
        DateTime testDate(); //자신이 아닌 다른 애너테이션(@DateTime)을 포함할 수 있다.
    }
    @interface DateTime{
    	String yymmdd();
        String hhmmss();
    }
    
    // 정의한 TestInfo 애너테이션 선언
    @TestInfo(
    	testBy = "Sool",
        testTools = {"JUnit", "AutoTester"},
        testType = testType.FIRST,
        testDate = @DateTime(yyyy = "220703", hhmmss="113100")
    }

    java.lang.annotation.Annotation

    애너테이션은 인터페이스이다. java.lang.annotation.Annotation에는 클래스가 없고 애너테이션은 인터페이스이다. 따라서 모든 애너테이션의 조상임에도 물구하고 상속을 허용되지 않고 조상으로 지정할 수도 없다.

    equals(), hashCode(), toString()과 같은 java.lang.Object 패키지의 기본 메소드를 호출할 수 있다. 그리고 annotationType()메소드를 호출하면 Class<? extends Annotation>애너테이션의 타입을 반환한다.

    마커 애너테이션 Marker Annotation

    값을 지정할 필요가 없는 경우, 애너테이션의 요소를 하나도 정의하지 않을 수 있다. Serializable이나 Cloneable인터페이스처럼 요소가 하나도 정의되지 않은 애너테이션을 말한다.

    애너테이션 요소의 규칙

    • 요소의 타입은 기본형, String, enum, 애너테이션, Class만 허용된다
    • ( ) 안에 매개변수를 선언할 수 없다.
    • 예외를 선언할 수 없다.
    • 요소를 타입 매개변수로 정의할 수 없다.

     

Designed by Tistory.