애너테이션이란 프로그램의 소스코드 안에 다른 프로그램을 위한 정보를 미리 약속된 형식으로 포함시킨 것이다.
마치 주석과도 같이 프로그래밍 언어에 영향을 미치지 않으면서도 다른 프로그램에게 유용한 정보를 제공할 수 있다는 장점이 있다. (스프링에서 사용되는 에너테이션은 영향을 미치지만, 우선 스프링이 아닌 기본 자바를 기준으로 설명하겠다.)
표준 애너테이션
자바에서 기본적으로 제공하는 애너테이션은 몇 개 존재하지 않는다.
게다가 그들 중 일부는 '메타 애너테이션'으로 애너테이션을 정의하는데 사용되는, 애너테이션을 위한 애너테이션이다.
자바에서 기본적으로 제공하는 표준 애너테이션의 종류는 다음과 같다.
애너테이션 | 설명 |
@Override | 컴파일러에게 메서드를 오버라이딩 하는 것이라고 알린다. |
@Deprecated | 앞으로 사용하지 않을 것을 권장하는 대상에 사용한다. |
@SuppressWarnings | 컴파일러의 특정 경고메세지가 나타나지 않게 해준다. |
@SafeVarargs | 지네릭스 타입의 가변인자(...)에 사용한다. |
@FunctionalInterface | 함수형 인터페이스라는 것을 알린다. |
@Native | native 메서드에서 참조되는 상수 앞에 붙인다. |
@Target* | 애너테이션이 적용가능한 대상을 지정하는데 사용한다 |
@Documented* | 애너테이션 정보가 javadoc으로 작성된 문서에 포함되도록 한다. |
@Inherited* | 애너테이션이 자손 클래스에 상속되도록 한다. |
@Retention* | 애너테이션이 유지되는 범위를 지정하는데 사용된다. |
@Repeatable* | 애너테이션을 반복해서 적용할 수 있게 한다. |
(*이 붙은 것은 메타 애너테이션이다.)
@Override
자주 접해보았을 것이다.
(사실 모르는 사람이 없을 것이라 생각하여 간단히만 소개하고 넘어가겠다)
메서드 앞에만 붙일 수 있는 애너테이션으로, 부모의 메서드를 오버라이딩 하는 것이라는 것을 컴파일러에게 알려주는 역할을 한다.
@Deprecated
새로운 버전이 계속해서 탄생함에 따라, 새로운 기능이 추가될 뿐만 아니라 기존의 부족했던 기능들이 개선된다.
이러한 과정 속에서 기존의 기능을 대체할 것들이 추가되어도, 이미 여러 곳에서 사용되고 있을 지 모르는 기존의 것들을 함부로 삭제할 수 없다. (하위 호완성을 유지하기 위함)
따라서 생각해 낸 방법이 바로 더 이상 사용되지 않는 필드나 메서드에 @Deprecated 애너테이션을 붙이므로써, 기존의 사용되던 것과의 호완성을 유지하며, 새롭게 개발하는 코드에서는 다른 것으로 대체되었으니 더 이상 사용하지 않을 것을 권한다는 의미이다.
예를 하나 보자. 자바의 Date 클래스이다.
@FunctionalInterface
함수형 인터페이스를 선언할 때, 컴파일러에게 올바르게 함수형 인터페이스를 선언했는지 확인하고, 잘못된 경우 에러를 발생시키게끔 만들어준다.
@SuppressWarnings
컴파일러가 보여주는 경고 메세지가 나타나지 않게 억제해준다.
컴파일러의 경고 메시지를 묵인해야 할 때가 종종 존재하는데, 이 경고를 그대로 놔두면 컴파일 할 때마다 메시지가 나타난다.
이렇게 묵인해야 하는 결고가 발생하는 대상에 @SuppressWarnings를 붙여서 컴파일 후에 어떤 경고 메세지도 나타나지 않게 해준다.
대표적으로 억제하는 경고 메세지는 "deprecation", "unchecked", "rawtypes", "varargs" 정도이다.
사용 예시는 다음과 같다.
@SuppressWarnings("unchecked")
ArrayList list = new ArrayList();
list.add(obj);
메타 애너테이션
앞서 잠깐 언급했듯이, 메타 애너테이션은 '애너테이션을 위한 애너테이션', 즉 애너테이션에 붙이는 애너테이션으로 애너테이션을 정의할 때 애너테이션의 적용대상(target)이나 유지기간(rentention) 등을 지정하는데 사용된다.
애너테이션 | 설명 |
@Target | 애너테이션이 적용가능한 대상을 지정하는데 사용한다 |
@Documented | 애너테이션 정보가 javadoc으로 작성된 문서에 포함되도록 한다. |
@Inherited | 애너테이션이 자손 클래스에 상속되도록 한다. |
@Retention | 애너테이션이 유지되는 범위를 지정하는데 사용된다. |
@Repeatable | 애너테이션을 반복해서 적용할 수 있게 한다. |
@Target
애너테이선이 적용가능한 대상을 지정하는 데 사용된다.
아래는 SuppressWarings 애너테이션의 정의인데, 한번 살펴보자.
@Target으로 여러 적용 대상을 정해주었다.
@Target으로 지정할 수 있는 애너테이션 적용대상의 종류는 아래와 같다.
대상 타입 | 의미 |
ANNOTATION_TYPE | 애너테이션 |
CONSTRUCTOR | 생성자 |
FIELD | 필드(멤버변수, enum 상수) |
LOCAL_VARIABLE | 지역변수 |
METHOD | 메서드 |
PACKAGE | 패키지 |
PARAMETER | 매개변수 |
TYPE | 타입(클래스, 인터페이스, enum) |
TYPE_PARAMETER | 타입 매개변수(<E>에서 E) |
TYPE_USE | 타입이 사용되는 모든 곳 |
TYPE은 타입을 선언할 때 이 애너테이션을 붙일 수 있다는 뜻이고, TYPE_USE는 해당 타입의 변수를 선언할 때 붙일 수 있다는 뜻이다.
@Rentention
애너테이션이 유지되는 기간을 지정하는데 사용된다.
종류는 다음과 같다.
유지 정책 | 의미 |
SOURCE | 소스 파일에만 존재. 클래스파일에는 존재하지 않음 |
CLASS | 클래스 파일에 존재. 실행시에 사용불가. 기본값. |
RUNTIME | 클래스 파일에 존재. 실행시에 사용가능 |
(소스 파일은 컴파일 이전, 클래스 파일은 컴파일 이후이다.)
@Documented
애너테이션에 대한 정보가 javadoc으로 작성한 문서에 포함되도록 한다.
@Inherited
애너테이션이 자손 클래스에 상속되도록 한다.
@Inherited가 붙은 애너테이션을 조상 클래스에 붙이면, 자손 클래스도 이 애너테이션이 붙은 것과 같이 인식된다.
@Inherited
@interface SuperAnno{}
@SuperAnno
class Parent{}
class Child extends Parent{} //Child에 에네테이션이 붙은 것으로 인식
@Repeatable
보통은 하나의 대상에 한 종류의 애너테이션을 붙이지만, 여러 번 붙일 수 있도록 만들어 줄 때 사용한다.
애너테이션 타입 정의하기
지금까지는 애너테이션을 사용하는 방법에 대해서 살펴보았고, 이제 애너테이션을 직접 만드는 방법에 대해서 알아보자.
간단하다.
@interface 애너테이션이름 {
타입 요소이름();
}
아래는 예시이다.
애너테이션의 요소
애너테이션 내에 선언된 메서드를 '애너테이션의 요소'라고 하며, 반환값은 있고, 매개변수는 없는 추상 메서드의 형태를 가진다.
애너테이션을 적용할 때 이 요소들의 값을 빠짐없이 지정해 주어야 하며, 순서는 상관없다.
만약 기본값을 지정해주고 싶다면, 다음과 같이 사용한다.
만약 요소의 타입이 배열이라면 괄호{}를 사용해서 여러 개의 값을 지정할 수 있다.
@Test(testTools={"JUnit", "AutoTester"})
'☕️ Java > 기본' 카테고리의 다른 글
[Java] 자바 JVM 메모리 관리 파헤치기 (스택, 힙, Reference Type, 가비지 컬렉터) (0) | 2022.01.24 |
---|---|
[Java] ThreadLocal에 대해 (0) | 2022.01.22 |
[Java] HashSet, LinkedHashSet, TreeSet (0) | 2022.01.21 |
[Java] 슈퍼 타입 토큰 (0) | 2022.01.03 |
[Java] 제네릭에 대하여 (타입이레이저, 변성) (2) | 2022.01.02 |