ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 어노테이션, 애너테이션(Annotation) - 표준 애너테이션
    백엔드/자바 2021. 5. 26. 11:25

    애너테이션이란?

    주석처럼 프로그램에 영향을 미치지 않으면서, 유용한 정보를 제공하는 것.

     

    간단히 말하면 코드 사이에 주석처럼 쓰이며 특별한 의미, 기능을 제공하는 것이다.

     

    애너테이션은 주석처럼 코드 사이에 존재하며, 코드에는 영향을 주지 않는 것이 특징이다.

     

    코드 변경 없이도 다양한 부가적인 정보를 제공하거나 기능을 수행하게 만든다.

    표준 애너테이션


    애너테이션


    설명


    @Override


    컴파일러에게 오버라이딩하는 메서드라는 것을 알려준다.


    @Deprecated


    앞으로 사용하지 않을 것을 권장하는 대상에 붙인다.


    @SuppressWarnings


    컴파일러의 특정 경고 메시지가 나타나지 않게 해준다.


    @SafeVarargs


    지네릭스 타입의 가변 인자에 사용한다.


    @FuntionalInterface


    함수형 인터페이스라는 것을 알린다.


    @Native


    native메서드에서 참조되는 상수 앞에 붙인다.


    @Target *


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


    @Documented *


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


    @Inherited *


    애너테이션이 자손 클래스에 상속 되도록 한다.


    @Retention *


    애너테이션이 유지되는 범위를 지정하는데 사용한다.


    @Repeatable *


    애너테이션을 반복적으로 적용하도록 한다.

     

    자바에서 기본적으로 제공하는 애터테이션은 위와 같이 그리 수가 많지 않다.

     

    자바에서 제공하는 기본 애너테이션은 수가 적고,

     

    그 중 대부분은 새로운 애너테이션을 정의하기 위한 메타 애너테이션(표에서 * 표시가 되있는 것)이다.

     

    이번 단락에서는 표준 애너테이션 중 메타를 제외한 애너테이션을 설명할 예정이다.

     

     

    @Override

    컴파일러에게 애너테이션이 달린 메서드가 오버라이딩 메서드라는 것을 알린다.

     

     

     

    예를 들어 위와 같이 eat() 메서드를 가진 Animal 추상 메서드가 있다고 가정해보자.

     

    Bird는 Animal을 상속받았는데, eat() 메서드를 오버라이딩해서 내용을 바꾸고 싶다.

     

     

     

    이때 만약 @Override를 쓰지 않고 오버라이딩 하면 메서드명이 틀리는 등의 실수를 할 수 있다.

     

    하지만 컴파일러는 내용상 오류가 없기 때문에 에러 체크를 하지 못한다.

     

    애초에 자손 클래스는 부모 클래스에 없는 메서드를 자체적으로 만들 수 있기 때문이다.

     

     

     

     

    이때 메서드 상단에 @Override를 달면 컴파일러가 해당 메서드가 오버라이딩 메서드인지 체크해준다.

     

    내용을 읽어보면 알겠지만 해당 메서드는 부모 클래스로부터 오버라이딩된 메서드가 아님을 알려준다.

     

    왜냐면 메서드명이 바뀌었기 때문이다.

     

    이런 식으로 @Override는 오버라이딩에서 생기는 실수를 체크해서 에러를 줄여줄 수 있다.

     

     

     

    이제 내용을 메서드명을 Eat () => eat() 으로 바꿔주니 에러가 사라진 것을 볼 수 있다.

     

     

    @Deprecated

    해당 애너테이션을 붙이면 해당 메서드나 필드는 더 이상 사용을 권장하지 않는다는 의미를 갖는다.

     

    무슨 이야기냐하면, 자바의 경우 하위 호환성을 굉장히 중요하게 생각한다.

     

    그렇다보니 자바 소스 코드를 새로 업데이트하더라도 과거에 작성된 코드를 싸그리 무시하지 않는다.

     

    한마디로 새로운 기능을 추가한다고 기존에 있던 기능을 마음대로 삭제하지 않는다는 것이다.

     

    하지만 사용자는 이러한 업데이트 사실을 모를 수도 있고, 예전 기능을 사용할 가능성이 있다.

     

    물론 예전 기능을 사용한다고 코드가 작동하지 않는 것은 아니지만, 효율성 등의 측면에서 좋지 않다.

     

    그렇다보니 이러한 사실을 알려주기 위해 @Deprecated가 존재한다.

     

     

     

    예를 들어 이전 @Override에서 단락에서 사용한 eat() 메서드에 @Deprecated를 붙여보자.

     

     

     

     

    그리고 나서 해당 메서드를 메인 메서드에서 사용하면 위와 같이 메서드에 줄이 쳐진 것을 볼 수 있다.

     

    그리고 마우스 커서를 갖다 대면 해당 메서드는 앞으로 사용하지 못할 수도 있다는 경고가 뜬다.

     

    일반적인 자바 사용자들이 직접 애너테이션을 쓰는 경우는 많이 없을 것이다.

     

    다만 남이 만든 오래된 코드 등을 다뤄야 할 일이 생기면 위와 같은 일이 발생하므로 알아두는 것이 좋다.

     

     

    @FunctionalInterface

    함수형 인터페이스에 붙이면, 컴파일러가 해당 인터페이스를 제대로 작성했는지 체크해준다.

     

    함수형 인터페이스에는 하나의 추상형 메서드만 가져야 한다는 제약이 있다.

     

    이것이 제대로 작성됐는지 컴파일러가 체크해주는 것이다.

     

    @Override와 비슷한 기능이다. 안붙여도 상관은 없지만, 실수를 줄이기 위해 붙이는 것이 좋다.

     

     

     

    예를 들어 위와 같은 인터페이스가 존재한다고 가정해보자.

     

    해당 인터페이스는 함수형 인터페이스로 만들고 싶다.

     

    그런데 컴파일러상으로는 어떠한 에러체크가 되지 않는다.

     

     

     

    이때 @FuntionlInterface를 붙여주면 해당 인터페이스가 함수형 인터페이스에 적절한지 체크해준다.

     

     

     

    에러 메시지를 확인해보면 해당 인터페이스에서 다수의 추상메서드가 발견됐다는 내용을 확인할 수 있다.

     

    위에서 말한대로 함수형 인터페이스는 하나의 추상 메서드만 가져야 하기 때문이다.

     

     

     

    에러 메시지 내용대로 하나의 메서드를 삭제해주니까 컴파일러 에러가 뜨지 않는 것을 확인할 수 있다.

     

     

    @SuppressWarnings

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

     

    해당 애너테이션을 쓰고 괄호 안에 막으려는 경고의 종류를 문자열로 지정하면 된다.

     

    상식적으로 봤을 때 경고 메시지가 뜨면 코드가 문제가 생길 수 있다는 것을 의미한다.

     

    그런데 왜 이걸 막는다는 걸까?

     

    가끔 코드를 작성하다보면 경고가 뜨더라도 실행을 우선적으로 해야할 경우가 생긴다.

     

    그럴 경우 @SuppressWarnings과 막으려는 경고의 종류를 적어두면 해당 경고는 뜨지 않는다.

     

    이건 단순히 경고가 뜨지 않는다는게 아니라 해당 경고를 코드 작성자가 이미 알고 있다는 확인의 뜻이다.

     

    @SuppressWarnings를 쓰면 이미 경고가 뜨는걸 알고 @SuppressWarnings로 막아두고 있는데,

     

    만약 지정하지 않는 다른 경고가 새로 떴을 때 확인하는 등의 행위가 가능하다.

     

     

     

    이전 단락들에서 사용했던 예제를 계속 사용해보자.

     

    위와 같이 @Deprecated 애너테이션이 달린 메서드를 가진 클래스를 컴파일 해보자.

     

     

     

    우선 윈도우 하단의 검색창에서 "cmd"를 검색해 명령 프롬프트를 실행한다.

     

     

     

    명령 프롬프트가 실행되면 cd + java 파일 경로를 입력해준다.

     

     

     

    경로로 진입해서 javac + 자바 파일명으로 자바 파일을 컴파일해준다.

     

     

     

    그럼 위와 같은 메시지가 뜬다.

     

    해석하면 deprecated API가 사용되었다는 뜻으로 우리가 @Deprecated를 사용해서 경고가 뜬 것이다.

     

    디테일한 경고 메시지를 보고 싶으면 -Xlint 명령어를 붙여서 다시 컴파일하면 된다.

     

     

     

    -Xlint 명령어를 붙여서 다시 컴파일을 하면 위와 같은 메시지와 어디가 문제인지 알 수 있다.

     

     

     

     

    에러 메시지를 조금 더 디테일하게 보면 해당 java파일의 14번째 줄에서 오류가 난 것을 볼 수 있다.

     

    다시 인텔리제이로 돌아가면 14번째 줄이 우리가 @Deprecated를 써준 메서드인 것을 볼 수 있다.

     

     

     

    이제 해당 에러 메시지를 막을 수 있도록 메인 메서드 상단에 @SuppressWarnings()를 써보자.

     

    이때 @SuppressWarnings()안에 막고싶은 에러를 적어두면 된다.

     

    @Deprecated 에러를 막으려면 "deprecation"을 쓰면 된다.

     

     

     

    만약 두 개 이상의 경고를 막고 싶다면 위와 같이 하면 된다.

     

    우선 위와 같이 @SuppressWarnings를 써주니 eat() 메서드에 쳐져있던 줄이 사라진 것을 볼 수 있다.

     

     

     

    명령 프롬프트를 통해 컴파일해도 이제 경고 메시지가 없이 컴파일이 완료된 것을 알 수 있다.

    메타애너테이션

    메타애너테이션을 애너테이션을 만들기 위해 필요한 애터테이션이다.

     

    일반적으로는 프로그램 내에서 이미 만들어진 애너테이션을 쓰는 경우가 대부분이다.

     

    다만 간혹 애너테이션을 만들어서 사용할 수 도 있기 때문에 이러한 경우를 위해 만든 것이다.

     

    메타 애너테이션은 애너테이션의 적용 대상, 수명 등을 지정하는데 사용된다.

     

     

    @Target

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

     

     

    위의 캡쳐는 이전 단락에서 사용한 @SuppressWarnings의 소스 코드다.

     

    애너테이션 상단을 보면 @Target 애너테이션을 확인할 수 있다.

     

    그리고 안에는 해당 애너테이션이 적용 가능한 대상을 적어둔 것이다.

     

    아래는 Target 애너테이션에 올 수 있는 명령어들이다.

     


    대상 타입


    의미


    ANNOTATIO_TYPE


    애너테이션


    CONSTRUCTOR


    생성자


    FIELD


    필드(멤버변수, enum상수)


    LOCAL_VARIABLE


    지역변수


    METHOD


    메서드


    PACKAGE


    패키지


    PARAMETER


    매개변수


    TYPE


    타입(클래스, 인터페이스, enum)


    TYPE_PARAMETER


    타입 매개변수


    TYPE_USE


    타입이 사용되는 모든 곳

     

    @Retention

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

     

     

    위의 캡쳐는 @SuppressWarnings의 소스코드다.

     

    여기서 상단을 보면 @Retention을 보면 해당 애너테이션의 유지 기간을 볼 수 있다.

     

    @SuppressWarnings은 컴파일 체크과정에서 경고를 막는 역할을 하므로 유지 기간이 SOURCE로 되있다.

     

    만약 바꾸고 싶다면 RetentionPolicy.+유지기간 형식으로 내용을 바꿔주면 된다.

     

    참고로 유지 기간 종류는 총 3개다.

     


    유지 기간


    의미


    SOURCE


    소스 파일에만 존재. 클래스 파일에는 존재하지 않음.


    CLASS


    클래스 파일에 존재. 실행시에 사용 불가. 기본값.


    RUNTIME


    클래스 파일에 존재. 실행시에 사용 가능.

     

    @Documented

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

     

     

    @Deprecated 애너테이션을 보면 상단에 @Documented가 달린 것을 알 수 있다.

     

    표준 애너테이션 중 @Override와 @SuppressWarnins를 제외하고 모두 달려있다.

     

    다만 일반적으로 쓰는 애너테이션을 아니라 크게 신경 쓸 건 없다.

     

     

    @Inherited

    애너테이션이 자손 클래스에 상속되도록 한다.


    해당 애너테이션을 조상 클래스에 붙이면, 상속 받은 자손 클래스도 이 애너테이션이 붙은 것과 같이 인식된다.

     

     

    @Repeatable

    보통 하나의 대상에는 한 종류의 애너테이션을 붙인다.

     

    @Repeatable이 붙은 애너테이션은 하나의 대상에 여러번 애너테이션을 붙일 수 있다.

     

    이때 주의 할 점은 @Repeatable이 붙은 애너테이션을 하나로 모아 담을 컨테이너 애너테이션도 정의해야 한다.

     

    글로만 보면 이해가 힘드니 예제로 보도록 하자.

     

     

     

    예를 들어 위와 같은 형식의 애너테이션이 있다고 가정해보자.

     

    애너테이션 안에 String 변수 하나를 가지고 있는 아주 단순한 애너테이션이다.

     

     

     

    이때 이 애너테이션을 한 대상에서 여러번 써주고자 @Repeatable을 붙여줬다.

     

    하지만 컴파일 오류가 난다.

     

    왜냐면 위에서 이야기한대로 아직 이 애너테이션을 하나로 모을 컨테이너 애너테이션이 없기 때문이다.

     

     

     

    위 캡쳐샷과 같이 컨테이너 애너테이션을 만들어보자.

     

    이름은 아무렇게나 지어도 되지만, 내부에는 대상이 되는 애너테이션을 담을 배열이 있어야 한다.

     

    그리고나서 @Repeatable() 안에 컨테이너 애너테이션을 지정해준다.

     

    그럼 위와 같이 컴파일 에러가 없어진 것을 확인할 수 있다.

     

     

     

    이제 직접 메서드 위에 테스트를 해보면 여러번 중복해서 애너테이션을 쓸 수 있는 것을 볼 수 있다.

Designed by Tistory.