-
10-1. 어노테이션과 리플렉션 : 어노테이션Study(종료)/Kotlin 22.09.13 ~ 12.18 2022. 11. 17. 18:02
10장
10-1. 어노테이션과 리플렉션 : 어노테이션
내가 알고 있는 어노테이션은 자바에서 @를 통해서 작성하는것이고,
@Override를 통해 사용했던 기억 정도밖에 없다. 이번 단원에서 좀 더 자세히 알아봐야겠다.
10-1. 어노테이션
책에서는 어노테이션은 커스텀 메타데이터를 정의하고
이 메타데이터를 소스코드상의 선언, 식, 전체 파일 등의 엮는 방법을 제공한다고 설명한다.
1) 어노테이션 클래스 정의하고 사용하기
어노테이션을 사용하는 가장 기본적인 방법은 선언 앞쪽 변경자 위치에
@이 붙은 어노테이션 이름을 적는 것 이다.
import org.junit.Test class MyTestCase{ @Test fun testOnePlusOne(){ assert(1 + 1 == 2) } }
코틀린 어노테이션을 식에 적용할 수도 있다.
val s = @Suppress("UNCHECKED_CAST") objects as List<String> // @Suppress 어노테이션을 이용해 소스 파일에 특정 식에 대한 컴파일러 경고를 끔
// 같은 구성 요소에 어노테이션을 여러 개 // 붙이고 싶다면 각괄호 ( [ ] )를 사용하면 된다. @[Suppress Strictfp] // @Suppress @Strictfp와 같은 역할 fun main() { }
// 어노테이션을 정의하는 방법 annotation class MyAnnotation @MyAnnotation fun annotatedFun(){ } // 어노테이션을 주생성자에 적용하는 경우 class A @MyAnnotation constructor()
코틀린 어노테이션은 특별한 종류의 클래스로 분류된다.
자바의 어노테이션은 인터페이스로 구성되므로, 정의 차이가 있다.
내포된 클래스, 인터페이스, 객체(+동반객체)를 어노테이션 본문에 넣을 수 있다.
annotation class MyAnnotation{ // val text = "abc" // ERROR : Members are not allowed in annotation class companion object{ val text = "abc" // OK } }
어노테이션에 커스텀 어트리뷰트를 추가하고 싶다면 생성자 파라미터를 통해서만 가능하다.
이와같은 어노테이션을 사용할 때는 클래스 생성자를 호출할 때 처럼 this 파라미터에 실제 인자를 제공해야 한다.
이 때 어노테이션 파라미터를 항상 val로 선언해야 한다.
annotation class MyAnnotation(val text: String) @MyAnnotation("Some Useful Info") fun annotatedFun(){}
일반적인 생성자와 마찬가지로 디폴트 값이나 가변 인자를 사용할 수 있다.
또한 코틀린 어노테이션은 클래스의 일종이지만, 일반적인 클래스의 방식으로 클래스의 인스턴스를 만들수는 없다.
대신 @ 구문을 이용해서 어노테이션의 인스턴스를 생성할 수 있다.
어노테이션 클래스에는 상위 타입을 명시하거나,
어노테이션 클래스를 상속하는 클래스를 정의하는것은 불가능하다.
어노테이션은 Any 클래스와 빈 Annotation인터페이스를 자동으로 상속하며
이 둘은 모든 어노테이션 클래스의 공통 상위 타입 역할을 한다.
어노테이션 인자는 컴파일 시에만 평가되므로, 어노테이션 인자에 임의의 식을 넣을 수는 없고,
컴파일러는 어노테이션 파라미터로 사용할 수 있는 타입의 종류를 아래와 같이 제한한다.
- Int, Boolean, Double같은 원시 타입
- String
- enum
- 다른 어노테이션
- 클래스 리터럴
- 위 나열된 타입들로 이루어진 배열
다른 어노테이션을 인자로 사용하는 경우에는 @ 접두사를 안붙여도 된다.
대신 일반 생성자처럼 어노테이션을 써야 한다.
annotation class Dependency(vararg val componentNames: String) annotation class Component( val name: String = "Core", val dependency: Dependency = Dependency() ) @Component("I/O") class IO @Component("Log", Dependency("I/O")) class Logger @Component(dependency = Dependency("I/O", "Log")) class Main
클래스 리터럴을 사용하면 KClass 타입의 리플렉션 객체로 클래스에 대한 표현을 얻을 수 있다.
KClass 타입은 자바 언어의 Class 타입에 해당하는 코틀린 클래스이다.
클래스 이름 뒤에 ::class 를 붙여 클래스 리터럴을 만들 수 있다.
위 코드를 이름 대신 클래스 리터럴을 사용하는 형태로 바꿀 수 있다.
annotation class Dependency(vararg val componentClasses: KClass<*>) annotation class Component( val name: String = "Core", val dependency: Dependency = Dependency() ) @Component("I/O") class IO @Component("Log", Dependency(IO::class)) class Logger @Component(dependency = Dependency(IO::class, Logger::class)) class Main
코틀린에서는 어노테이션을 사용하는 시점에 어떤 대상에 대해 어노테이션을 붙이는지 지정할 수 있다.
이를 사용 지점 대상(use-site target)이라고 한다.
코틀린 소스가 여러 언어 요소가 함축되어 있는 선언에 대해 어노테이션을 붙이는 경우
class Person(val neame: String)
이 코드는 생성자 파라미터, 게터가 있는 클래스 프로퍼티,
프로퍼티 값을 저장하기 위한 backing-field 선언을 짧게 줄인 코드이다.
이 요소 각각에 대해 어노테이션을 붙일 수 있으므로
코틀린에서는 어노테이션을 사용하는 시점에 어떤 대상에 대해 어노테이션을 붙이는지 지정할 수 있다.
이러한 use-site target은 특별한 키워드를 통해 지정한다.
이 키워드는 어노테이션 이름 앞에 붙으며 :(콜론)으로 어노테이션 이름과 구분된다.
프로퍼티 게터에 대한 어노테이션을 붙이고 싶은경우 아래와 같이 작성하면 된다.
class Person(@get:A val neame: String)
대부분의 use-site targe은 다양한 프로퍼티 구성 요소와 연관돼 있다.
use-site target의 위치에 따라 의미하는 target은 다음과 같다.
- property : 프로퍼티 자체가 target
- field : backing-field가 target(backing-field가 있는 프로퍼티에 대해서만 동작)
- get : 프로퍼티 게터가 taget
- set : 프로퍼티 세터가 target
- param : 생성자 파라미터가 target(val/var가 붙은 파라미터에 대해서만 대상으로 지정 가능)
- setparam : 프로퍼티 세터의 파라미터가 taget(var 프로퍼티에 대해서만 동작)
- delegate : delegate 객체를 저장하는 필드가 target(deleget 프로퍼티에 대해서만 동작)
2) 내장 어노테이션
코틀린에서 제공하는 몇 가지 내장 어노테이션이 있다. 이들은 컴파일러 수준에서 특별한 의미를 가진다고 한다.
- @Retention
- 어노테이션이 저장되고 유지되는 방식을 제어
- 자바의 @Rentention 인터페이스와 유사
- SOURCE, BINARY, RUNTIME 저장 방식을 지정 가능
- @Repetable
- 기본적으로 어노테이션을 반복 적용하는 것은 불가능
- 이 어노테이션을 사용하면 같은 언어 요소에 두 번 이상 반복 적용 가능
- @MustBeDocumented
- 문서에 꼭 포함시키라는 의미
- 자바의 @Documented와 동일한 역할
- @Target
- 어노테이션을 어떤 언어 요소에 붙일 수 있는지 지정
- Annotation enum에 정의된 상수들을 vararg로 지정
- 상수는 CLASS, ANNOTATION_CLASS, TYPRALIAS, PROPERTY 등 존재
- 자바 변경자와 같은 역할을 하는 어노테이션
- @StrictFp : 부동소수점 연산의 정밀도 제한 > 다른 플랫폼 간 부동소수점 연산 이식성 향상
- @Synchronized : 동시성 지원 관련
- @Volatitle : 동시성 지원 관련
- @Translent : 어노테이션이 붙은 필드를 직렬화 메커니즘이 무시
- @Deprecated
- 어떤 선언을 사용 금지 예정(deprecated)라고 선언할 경우
- 이 선언을 사용하지 않는 것을 클라이언트 코드에게 권장
- 자바와 @Deprecated 어노테이션과 동일한 역할
- 내부에 @ReplaceWith 어노테이션을 선언해 대안을 제공 가능
다음글
반응형'Study(종료) > Kotlin 22.09.13 ~ 12.18' 카테고리의 다른 글
11-1-1. 도메인 특화 언어 : 연산자 오버로딩(1~5) (0) 2022.11.24 10-2. 어노테이션과 리플렉션 : 리플렉션 (0) 2022.11.19 9-3. 제네릭스 : 타입 별명(Type Alias) (0) 2022.11.13 9-2. 제네릭스 : 변성 (Variance) (0) 2022.11.13 9-1. 제네릭스 : 타입 파라미터 (0) 2022.11.10