Live Study 12주차 - Annotation


애노테이션 정의하는 방법

Enum과 함께 Java 1.5에 추가된 기능이다.

애노테이션이란 프로그램의 소스코드 안에 다른 프로그램을 위한 정보를 미리 약속된 형식으로 포함시켜주는 역할을한다.

주석처럼 프로그래밍 언어에 영향을 미치지 않으면서 정보를 제공할 수 있는 장점이 있다.

애노테이션 정의

아래는 흔히 사용하는 @Override 애노테이션이 정의된 코드이다.

1
2
3
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.SOURCE)
public @interface Override { }

애노테이션은 반환타입에 @interface를 입력하면 애노테이션으로 사용할 수 있다.

@Target, @Retention애노테이션을 위한 애노테이션이다. 이를 메타 애노테이션이라 한다.


애노테이션 사용

클래스나 메서드 위에 애노테이션을 작성하여 컴파일러에게 알려준다.

1
2
@Test   // 이 메서드가 Test 메서드임을 알린다.
public void LiveStudyTest() { }

표준 애노테이션

자바에서 기본적으로 제공하는 애노테이션이다.

@Override

컴파일러에게 오버라이딩하는 메서드임을 알리는 애노테이션이다.

생략해도 문제는 없지만, @Override를 사용함으로써 오버라이딩이 제대로 적용되었는지를 컴파일러로부터 체크받을수 있기때문에 사용하는것이 좋다.

@Deprecated

앞으로 사용하지 않은 대상이라고 알리는 애노테이션이다.

@SuppressWarnings()

컴파일러의 경고메세지가 나타나지 않게 해주는 애노테이션이다. 작은 범위에서 사용해야 한다.

@SuppressWarnings() 애노테이션으로 억제할 수 있는 경고 메세지의 종류는 다음과 같다.

경고 메세지 설명
deprecation @Deprecated 애노테이션이 붙은 대상(필드, 메서드)를 사용해서 발생하는 경고를 억제한다.
unchecked 제네릭으로 타입 지정을 하지 않았을때 발생하는 경고를 억제한다.
rawtypes 제네릭을 사용하지 않아서 발생하는 경고를 억제한다.
varargs 가변인자의 타입이 제네릭 타입일때 발생하는 경고를 억제한다.

가변인자란, 파라미터를 가변적으로 조정할 수 있는 기술을 의미한다.
가변인자를 사용해서 인자로 들어오는 int형 배열의 요소 합을 반환하는 메서드 예제코드이다.

1
2
3
4
5
6
7
public int addNumbers(int[] ... numbers){
int result = 0;
for(int num : numbers){
result += num;
}
return result;
}

여러개의 경고 메세지를 억제하고 싶다면, 배열처럼 파라미터에 경고 메세지를 담으면 된다.

1
@SuppressWarnings({"deprecation", "unchecked"})

@FunctionalInterface

함수형 인터페이스라는 것을 알린다. 애노테이션을 사용함으로써 컴파일러가 함수형 인터페이스를 올바르게 선언했는지 체크해준다.

이 애노테이션을 사용하기 위해서는 대상이 되는 추상메서드가 반드시 하나뿐이어야 한다.

1
2
3
4
@FuntionalInterface
public interfcae Runnable {
public abstract void run();
}

@SafeVarargs

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

@Native

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

Native Method란 C, C++같은 네이티브 언어로 작성된 메서드를 말한다.
이런 native 메서드를 호출하는 기술을 JIN(Java Native Interface)라고 한다.

출처 : Kimtaeng - [이펙티브 자바 3판] 아이템 66. 네이티브 메서드는 신중히 사용하라



여기부터는 메타 에노테이션 목록이다.

메타 애노테이션이란, 애노테이션을 위한 애노테이션을 의미한다. 애노테이션의 대상(target)이나 유지기간(retention)을 지정하는데 사용된다.

@Target

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

@SuppressWarnings를 정의한 코드이다.

1
2
3
4
5
@Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE})
@Retention(RetentionPolicy.SOURCE)
public @interface SuppressWarnings {
String[] value();
}

@Retention

애노테이션이 유지되는 기간을 지정할때 사용한다.

유지정책 의미
SOURCE 소스 파일에만 존재, 클래스 파일에는 존재하지 않는다.
컴파일러에서 사용하는 애노테이션의 유지 정책이다.
CLASS 클래스 파일에 존재, 실행시에 사용불가하다. 기본값이다.
컴파일러가 애노테이션의 정보를 클래스 파일에 저장할 수 있게하지만, 클래스 파일이 JVM에 로딩될때 애노테이션의 정보가 무시되어 실행 시에 애노테이션에 대한 정보를 얻을 수 없다.
RUNTIME 클래스 파일에 존재, 실행시에 사용가능하다.
실행시에 리플렉션(reflection)을 통해 클래스 파일에 저장된 애노테이션의 정보를 읽어서 처리할 수 있다.
1
2
3
@Target(ElementType.METHOD)
@Retention(RetenPolicy.SOURCE)
public @interface Override { }

@Override는 소스 파일에만 존재하고, 클래스 파일에는 존재하지 않는다. 클래스 파일이 없다는건 JVM에서 관리하지 않는다는 것으로 이해하고 있다.
이와같은 애노테이션으로는 @SuppressWarnings가 있다.

지역변수에 붙는 애노테이션은 컴파일러만 인식하므로 유지정책이 RUNTIME 이어도 실행시에 유지되지 않는다.

@Documented

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

1
2
3
4
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface FunctionalInterface(){ }

@Inherited

애노테이션이 자손 클래스에 상속되도록 하는 애노테이션이다. 애노테이션에 @inherited를 사용하면, 이를 상속받는 클래스에도 해당 애노테이션이 상속된다.

@Inherited는 클래스나 메서드가 아니라 애노테이션을 정의하는 영역에서 사용하는 애노테이션이다.

1
2
3
4
5
6
7
@Inherited
@interface SupperAnno { }

@SuperAnno
class Parent { }

class Child extends Parent { }

Child 클래스엔 애노테이션이 없지만, 부모 클래스 Parent의 @SuperAnno@Inherited를 메타 애노테이션을 갖으므로 자식 클래스인 Child 클래스에도 @SupperAnno가 상속된다.


애노테이션 프로세서

애노테이션 프로세싱은 Java 5 에서 추가된 기술로서 컴파일 타임에서 사용자가 정의한 어노테이션의 코드를 분석하고 처리하기 위해 사용되는 훅(Hook)이다.

Lombok이 이를 활용한 대표적인 라이브러리이다.

애노테이션 프로세싱은 추가적으로 학습이 더 필요할것 같다.