Kotlin-34.注解(Annotation)

官方文檔: http://kotlinlang.org/docs/reference/annotations.html

1.聲明注解(Annotation Declaration)

和java類似,kotlin注解就是在代碼中附加元數據(metadata),
聲明注解(在class前面添加annotation修飾符):
    annotation class Fancy

和java注解類似,kotlin注解的附加屬性可以通過元注解(meta-annotation)來聲明指定,
kotlin元注解(meta-annotation)有以下幾種:
    @Target 注解目標: 指定該注解用于什么類型的元素(類,函數,屬性,表達式等);
    @Retention 注解保留: 指定該注解是否存在編譯后的class文件,以及在運行時能否通過反射可見(默認都是true);
    @Repeatable 允許該注解在單個元素上多次使用;        
    @MustBeDocumented 指定該注解是公有API的一部分,且應該包含在生成的API文檔中(類或方法的文檔注釋)

注解聲明(包括元注解)的示例:
    @Target(AnnotationTarget.CLASS, //用于類
            AnnotationTarget.FUNCTION, //用于函數
            AnnotationTarget.VALUE_PARAMETER, //用于函數參數
            AnnotationTarget.EXPRESSION) //用于表達式
    @Retention(AnnotationRetention.SOURCE) //表示注解只存在源碼,不在編譯后的class文件
    @MustBeDocumented //包含在API文檔中
    annotation class Fancy

2.使用注解(Usage)

@Fancy class Foo {
    @Fancy fun baz(@Fancy foo: Int): Int {
        return (@Fancy 1)
    }
}

1.對類的主構造函數進行注解,需要在構造函數前面添加constructor關鍵字,注解添加到它的前面:
    class Foo @Inject constructor(dependency: MyDependency) {
        //...
    }
    
2.對屬性訪問器(get/set)進行注解:
    class Foo {
        var x: MyDependency? = null
            @Inject set
    }

3.對Lambda表達式進行注解:    
    annotation class Suspendable

    val f = @Suspendable { Fiber.sleep(10) }

3.聲明注解的構造函數(Constructors)

注解可以有構造函數(用于接受參數):
    //聲明注解
    @Target(AnnotationTarget.CLASS)        
    annotation class Special(val why: String)

    //使用注解
    @Special("example") class Foo {}

1.kotlin注解的參數類型:
    和Java原生類型對應的kotlin類型(Int,Long等);
    字符串string;
    kotlin類class(Foo::class);
    枚舉enum;
    其它注解;
    以上類型構成的數組; 

    提示: 注解參數不能有可空(null)類型,因為JVM不支持存儲null作為注解屬性值!

2.注解作為另一個注解的參數,不需要添加@前綴:
    annotation class ReplaceWith(val expression: String)

    //ReplaceWith作為注解參數時,不需要加@前綴
    annotation class Deprecated(
            val message: String,
            val replaceWith: ReplaceWith = ReplaceWith(""))

    @Deprecated("This function is deprecated, use === instead", 
        ReplaceWith("this === other"))

3.kotlin類作為注解的參數
如果需要將一個類指定為注解的參數,請用Kotlin類(KClass),
Kotlin編譯器會自動將Kotlin類轉換為Java類,以便Java代碼能正常使用該注解和參數!
    import kotlin.reflect.KClass
    annotation class Ann(val arg1: KClass<*>, val arg2: KClass<out Any?>)

    @Ann(String::class, Int::class) class MyClass

4.精確注解/使用處目標(Annotation Use-site Targets)

當對屬性或主構造函數參數進行注解時,一個Kotlin屬性元素會生成多個Java元素,
說白了就是,主構造函數參數(有val/var)就是kotlin類屬性,
而[kotlin類屬性]就相當于[Java類field字段+get方法+set方法],
因此在kotlin源碼編譯成Java字節碼時,該注解可能同時在多個元素上!

1.對屬性元素(set/get/field/param)進行精確注解:
    //Ann是注解,@xx:是固定語法
    class Example(@field:Ann val foo, //對Java 字段 進行注解
                @get:Ann val bar,     //對Java get方法 進行注解
                @param:Ann val quux)  //對Java 構造函數參數 進行注解

2.同一目標元素有多個注解,可在方括號[]添加多個注解,空格分隔:
    class Example {
        //collaborator的set方法有兩個注解Inject和VisibleForTesting
        @set:[Inject VisibleForTesting] 
        var collaborator: Collaborator
    }

3.使用相同語法注解整個文件,把@file注解放在文件的頂層(package指令之前):
    @file:JvmName("Foo")
    package org.jetbrains.demo

4.使用處目標(use-site target)的完整列表:
    @file:
    @property: (具有此目標的注解對Java不可見)
    @field:
    @get:      (屬性的getter方法)
    @set:      (屬性的setter方法)
    @receiver: (擴展函數或屬性的接收者參數)
    @param:    (構造函數參數)
    @setparam: (屬性的setter方法參數)
    @delegate: (為委托屬性存儲其委托實例對象的字段)

    對擴展函數的接收者參數進行注解,語法如下:
        fun @receiver:Fancy String.myExtension() { }

    如果不指定使用處目標,則根據注解的@Target來選擇目標,有多個適用目標,
    則用以下列表的第一個目標:
        param
        property
        field

5.在Kotlin中使用Java注解(Java Annotation)

Java注解 與Kotlin 100%兼容,示例如下:
    // 導入Java注解
    import org.junit.Test
    import org.junit.Assert.*
    import org.junit.Rule
    import org.junit.rules.*

    // kotlin代碼,使用java注解
    class Tests {
        // @Rule注解用于tempFolder屬性的getter方法/函數
        @get:Rule val tempFolder = TemporaryFolder()

        // @Test注解用于simple方法/函數
        @Test fun simple() {
            val f = tempFolder.newFile()
            assertEquals(42, getTheAnswer())
        }
    }

1.因為Java聲明的注解沒有定義參數順序,所以kotlin需要使用命名參數來傳遞注解參數:
    // Java代碼,聲明注解Ann
    public @interface Ann {
        int intValue();
        String stringValue();
    }

    // Kotlin代碼,命名參數傳遞注解參數
    @Ann(intValue = 1, stringValue = "abc") class C

2.在Java注解中,有一個特殊的value參數無需顯式指定參數名:
    // Java
    public @interface AnnWithValue {
        String value();
    }

    // Kotlin
    @AnnWithValue("abc") class C

3.如果Java注解的value參數類型是數組,那么在Kotlin中該參數類型就是vararg(參數個數可變):
    // Java
    public @interface AnnWithArrayValue {
        String[] value();
    }
    // Kotlin,參數類型是vararg(參數個數可變),相當于數組
    @AnnWithArrayValue("abc", "foo", "bar") class C

4.如果Java注解的其它參數類型是數組,那么在Kotlin中該參數需要顯式使用arrayOf:
    // Java
    public @interface AnnWithArrayMethod {
        String[] names();
    }
    
    // Kotlin
    @AnnWithArrayMethod(names = arrayOf("abc", "foo", "bar")) class C

5.Java注解實例對象值會作為Kotlin屬性,暴露給Kotlin代碼:
    // Java
    public @interface Ann {
        int value();
    }

    // Kotlin
    fun foo(ann: Ann) {
        val i = ann.value
    }

簡書:http://www.lxweimin.com/p/7ec60cc61c7b
CSDN博客: http://blog.csdn.net/qq_32115439/article/details/74781883
GitHub博客:http://lioil.win/2017/07/07/Kotlin-annotation.html
Coding博客:http://c.lioil.win/2017/07/07/Kotlin-annotation.html

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容