Skip to content

Annotation & Reflection

어노테이션 적용

코틀린에서는 자바와 같은 방법으로 어노테이션을 사용할 수 있다. 어노테이션을 적용하려면 적용하려는 대상 앞에 어노테이션을 붙이면 된다. 어노테이션은 @어노테이션명으로 이루어져 있다.

어노테이션은 함수, 클래스, 프로퍼티 등 다양한 구성요소에 붙일 수 있다.

예를 들자면 @Deprecated 어노테이션이 있다. 자바의 Deprecated 어노테이션과 의미는 똑같다. 그러나 코틀린에서는 replaceWith 파라미터를 통해 대안을 제시할 수 있다.

kotlin
@Deprecated("Use removeAt (index) instead.", ReplaceWith("removeAt(index)"))
fun remove(index: Int) { ... }

어노테이션에 인자를 넘길때는 일반 함수처럼 괄호안에 파라미터를 전달한다. 어노테이션의 파라미터에는 다음과 같은 값이 들어갈 수 있다.

  • 원시타입의 값
  • 문자열
  • enum 클래스 참조
  • 다른 어노테이션 클래스
  • 위 요소들로 이뤄진 배열

그리고 파라미터를 지정하는 문법이 자바와 약간 다르다.

  • 클래스를 어노테이션의 파라미터로 전달할 때는 클래스명 뒤에 ::class를 클래스 이름 뒤에 넣어야한다.
  • 다른 어노테이션을 인자로 전달할때는 인자로 들어가는 어노테이션의 이름 앞에 @를 넣지 않아야한다. 위의 예재에서 ReplaceWith는 어노테이션이다. 따리서 앞에 @를 사용하지 않았다.

어노테이션 인자를 컴파일 시점에 알 수 있어야한다. 따라서 임의의 프로퍼티를 인자로 지정할 수 없다. 프로퍼티를 인자로 사용하려면 그 앞에 const 변경자를 붙여야 한다. 이는 컴파일러가 const가 붙은 프로퍼티를 컴파일 시점 상수로 취급한다.

어노테이션 선언

어노테이션을 선언하는 방법은 다음과 같다.

kotlin
annotation class MyAnnotation

어노테이션 클래스는 오직 선언이나 식과 관련있는 metadata의 구조를 정의하기 때문에 내부에 아무 코드도 들어있을 수 없다. 그런 이유로 컴파일러는 어노테이션 클래스에서 본문을 정의하지 못하게 한다.

파라미터가 있는 어노테이션을 정의하려면 어노테이션 클래스의 주 생성자에 파라미터를 선언해야한다.

kotlin
annotation class MyAnnotation(val name: String)

어노테이션에서는 모든 파라미터는 읽기 전용으로 선언한다.

자바는 다음과 같다.

java
public @interface MyAnnocation {
  String value();
}

여기서 코틀린은 name 프로퍼티를 사용했지만 자바는 value라는 메서드를 사용했다.

자바의 value 메소드는 특별하다. 어떤 어노테이션을 적용할 때 value를 제외한 모든 프로퍼티에는 이름을 명시해야 한다.

여기서 어노테이션의 생성자의 첫번째 인자이므로 다음은 같다.

kotlin
@MyAnnotation(name = "a")

@MyAnnotation("a")

메타 어노테이션

어노테이션 클래스도 마찬가지로 어노테이션을 붙일 수 있다. 이를 메타 어노테이션이라고 한다.

표준 라이브러리에는 몇가지 메타어노테이션이 있다. 이는 컴파일러가 어노테이션을 처리하는 방법을 제어한다.

가장 흔히 쓰이는 메타어노테이션은 @Target이다. 어노테이션의 적용 가능 대상을 지정하기 위해 사용되는 메타어노테이션이다. 위 메타어노테이션이 없으면 해당 어노테이션은 모든 요소에 적용할 수 있는 어노테이션이 된다.

kotlin
@Target(AnnotationTarget.PROPERTY)
annotation class MyAnnotation

그리고 @Retention 어노테이션이 있다. 이는 자바에서는 어노테이션은 런타임에는 사용하지 않도록 기본값을 가진다. 그러나 대부분의 경우 런타임에도 사용하기 때문에 @Retention(AnnotationRetention.RUNTIME)으로 지정한다.

리플렉션

리플렉션은 런타임에 객체의 프로퍼티와 메소드에 접근할 수 있도록 해주는 방법이다.

보통 컴파일 단계에서 구체적으로 타입으로 선언되어 있거나 메소드나 프로퍼티를 참조하여 컴파일러가 선언이 실제로 존재함을 보장해준다. 그러나 타입과 관계없이 객체를 다루거나 객체가 제공되는 런타임에서만 알 수 있는 경우가 있다. 대표적으로 JSON 직렬화 라이브러리가 그런 경우다.

코틀린에서 리플렉션을 사용하려면 두가지 서로 다른 리플렉션 API를 사용해야한다. 첫번째는 자바가 java.lang.reflect 패키지를 통해 제공하는 표준 리플렉션이다. 두번째 API는 코틀린이 kotlin.reflect 패키지를 통해 제공하는 코틀린 리플렉션이다.

코틀린 리플렉션 API

코틀린 리플렉션 API를 사용할때 접하게 되는 것은 클래스를 표현하는 KClass다. java.lang.Class에 해당하는 KClass를 사용하면 클래스 안에 있는 모든 선언을 열거하고 각 선언에 접근하거나 부모 클래스를 얻는 등의 작업이 가능하다.

책에는 더 많은 내용을 설명해주니 책에서 필요할때 살펴보는 것도 좋다.

Email: echo.youn@kakao.com