ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 10-1. 어노테이션과 리플렉션 : 어노테이션
    Study(종료)/Kotlin 22.09.13 ~ 12.18 2022. 11. 17. 18:02

    10장

    10-1. 어노테이션과 리플렉션 : 어노테이션

    10-2.  어노테이션과 리플렉션 : 리플렉션


    내가 알고 있는 어노테이션은 자바에서 @를 통해서 작성하는것이고,

    @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 어노테이션을 선언해 대안을 제공 가능

    다음글

    10-2.  어노테이션과 리플렉션 : 리플렉션

    반응형

    댓글

Designed by Tistory.