第七色在线视频,2021少妇久久久久久久久久,亚洲欧洲精品成人久久av18,亚洲国产精品特色大片观看完整版,孙宇晨将参加特朗普的晚宴

Kotlin 的注解

從這篇文章我們一起來看下 Kotlin 中的注解。Kotlin 中的注解是 100% 與 Java 注解兼容的,有很多相同的地方,但是也有一些不同的地方。一起來瞅瞅吧~

1. 注解的本質(zhì)

注解實際上就是一種代碼標簽,它作用的對象是代碼。它可以給特定的注解代碼標注一些額外的信息。然而這些信息可以選擇不同保留時期,比如源碼期、編譯期、運行期。然后在不同時期,可以通過某種方式獲取標簽的信息來處理實際的代碼邏輯,這種方式常常就是我們所說的反射。

2. 注解的定義

在 Kotlin 中注解核心概念和 Java 一樣,注解就是為了給代碼提供元數(shù)據(jù)。并且注解是不直接影響代碼的執(zhí)行。一個注解允許你把額外的元數(shù)據(jù)關(guān)聯(lián)到一個聲明上,然后元數(shù)據(jù)就可以被某種方式(比如運行時反射方式以及一些源代碼工具)訪問。

3. 注解的聲明

在 Kotlin 中的聲明注解的方式和 Java 稍微不一樣,在 Java 中主要是通過 @interface關(guān)鍵字來聲明,而在Kotlin 中只需要通過 annotation class 來聲明, 需要注意的是在 Kotlin 中編譯器禁止為注解類指定類主體,因為在 Kotlin 中注解只是用來定義關(guān)聯(lián)的聲明和表達式的元數(shù)據(jù)的結(jié)構(gòu)。

  • Kotlin 注解聲明
package com.mikyou.annotation
//和一般的聲明很類似,只是在class前面加上了annotation修飾符
annotation class TestAnnotation(val value: String)
  • Java 注解聲明
package com.mikyou.annotation;
//java中的注解通過@interface關(guān)鍵字進行定義,它和接口聲明類似,只不過在前面多加@
public @interface TestAnnotation {
    String value();
}

4. 注解的應(yīng)用

在上一步我們知道了如何聲明和定義標簽了,那么接下來就是用這個標簽,如何把我們定義好的標簽貼到指定的代碼上。在 Kotlin 中使用注解和 Java 一樣。要應(yīng)用一個注解都是 @注解類名

@Target(AnnotationTarget.FUNCTION)
@Retention(value = AnnotationRetention.RUNTIME)
annotation class TestAnnotation(val value: Int)//和一般的聲明很類似,只是在class前面加上了annotation修飾符

class Test {
    @TestAnnotation(value = 1000)
    fun test() {//給test函數(shù)貼上TestAnnotation標簽(添加TestAnnotation注解)
        //...
    }
}

在很多常見的 Java 或 Kotlin 框架中大量使用了注解,比如我們最常見的 JUnit 單元測試框架:

class ExampleUnitTest {
    @Test //@Test注解就是為了告訴JUnit框架,這是一個測試方法,當做測試調(diào)用。
    fun addition_isCorrect() {
        assertEquals(4, 2 + 2)
    }
}

Kotlin 中注解類中還可以擁有注解類作為參數(shù),不妨來看下 Kotlin 中對 @Deprecated這個注解源碼定義,以及它的使用。@Deprecated 注解在原來的 Java 基礎(chǔ)增強了一個 ReplaceWith 功能.??梢灾苯釉谑褂昧死系?API 時,編譯器可以根據(jù) ReplaceWith 中的新 API,自動替換成新的 API。這一點在 Java 中是做不到的,你只能點擊進入這個 API 查看源碼來正確使用新的 API。

//@Deprecated注解比Java多了ReplaceWith功能, 這樣當你在調(diào)用remove方法,編譯器會報錯。使用代碼提示會自動IntelliJ IDEA不僅會提示使用哪個函數(shù)提示替代它,而且會快速自動修正。
@Deprecated("Use removeAt(index) instead.", ReplaceWith("removeAt(index)"), level = DeprecationLevel.ERROR)//定義的級別是ERROR級別的,這樣當你在調(diào)用remove方法,編譯器會報錯。
@kotlin.internal.InlineOnly
public inline fun <T> MutableList<T>.remove(index: Int): T = removeAt(index)

@Deprecated 注解的 remove 函數(shù)使用:

//Deprecated注解的使用
fun main(args: Array<String>) {
    val list = mutableListOf("a", "b", "c", "d", "e")
    list.remove(3)//這里會報錯, 通過remove函數(shù)注解定義,這個remove函數(shù)在定義的level是ERROR級別的,所以編譯器直接拋錯
}

圖片描述

圖片描述

最后來看下 @Deprecated 注解的定義:

@Target(CLASS, FUNCTION, PROPERTY, ANNOTATION_CLASS, CONSTRUCTOR, PROPERTY_SETTER, PROPERTY_GETTER, TYPEALIAS)
@MustBeDocumented
public annotation class Deprecated(
        val message: String,
        val replaceWith: ReplaceWith = ReplaceWith(""),//注解類中構(gòu)造器可以使用注解類作為函數(shù)參數(shù)
        val level: DeprecationLevel = DeprecationLevel.WARNING
)
@Target()
@Retention(BINARY)
@MustBeDocumented
public annotation class ReplaceWith(val expression: String, vararg val imports: String)

注意:注解類中只能擁有如下類型的參數(shù): 基本數(shù)據(jù)類型、字符串、枚舉、類引用類型、其他的注解類(例如Deprecated注解類中的ReplaceWith注解類)

5. Kotlin 中的元注解

和 Java 一樣在 Kotlin 中,一個 Kotlin 注解類自己本身也可以被注解,可以給注解類加注解。我們把這種注解稱為元注解,可以把它理解為一種基本的注解,也可以把它理解為一種特殊的標簽,用于標注標簽的標簽。

Kotlin 中的元注解類定義于 kotlin.annotation 包中,主要有: @Target、@Retention、@Repeatable@MustBeDocumented 4 種元注解, 相比 Java 中 5 種元注解: @Target、@Retention、@Repeatable、@Documented、**@Inherited **少了 @Inherited元注解。

5.1 @Target 元注解

介紹

Target 顧名思義就是目標對象,也就是這個標簽作用于哪些代碼中目標對象,可以同時指定多個作用的目標對象。

源碼定義

@Target(AnnotationTarget.ANNOTATION_CLASS)//可以給標簽自己貼標簽
@MustBeDocumented
//注解類構(gòu)造器參數(shù)是個vararg不定參數(shù)修飾符,所以可以同時指定多個作用的目標對象
public annotation class Target(vararg val allowedTargets: AnnotationTarget)

@Target 元注解作用的目標對象

在@Target注解中可以同時指定一個或多個目標對象,那么到底有哪些目標對象呢?這就引出另外一個AnnotationTarget 枚舉類:

public enum class AnnotationTarget {
    CLASS, //表示作用對象有類、接口、object對象表達式、注解類
    ANNOTATION_CLASS,//表示作用對象只有注解類
    TYPE_PARAMETER,//表示作用對象是泛型類型參數(shù)(暫時還不支持)
    PROPERTY,//表示作用對象是屬性
    FIELD,//表示作用對象是字段,包括屬性的幕后字段
    LOCAL_VARIABLE,//表示作用對象是局部變量
    VALUE_PARAMETER,//表示作用對象是函數(shù)或構(gòu)造函數(shù)的參數(shù)
    CONSTRUCTOR,//表示作用對象是構(gòu)造函數(shù),主構(gòu)造函數(shù)或次構(gòu)造函數(shù)
    FUNCTION,//表示作用對象是函數(shù),不包括構(gòu)造函數(shù)
    PROPERTY_GETTER,//表示作用對象是屬性的getter函數(shù)
    PROPERTY_SETTER,//表示作用對象是屬性的setter函數(shù)
    TYPE,//表示作用對象是一個類型,比如類、接口、枚舉
    EXPRESSION,//表示作用對象是一個表達式
    FILE,//表示作用對象是一個File
    @SinceKotlin("1.1")
    TYPEALIAS//表示作用對象是一個類型別名
}

5.2 @Retention 元注解

介紹

Retention 對應(yīng)的英文意思是保留期,當它應(yīng)用于一個注解上表示該注解保留存活時間,不管是Java還是Kotlin 一般都有三種時期: 源代碼時期(SOURCE)編譯時期(BINARY)、運行時期(RUNTIME)

源碼定義

@Target(AnnotationTarget.ANNOTATION_CLASS)//目標對象是注解類
public annotation class Retention(val value: AnnotationRetention = AnnotationRetention.RUNTIME)//接收一個參數(shù),該參數(shù)有個默認值,默認是保留在運行時期

@Retention 元注解的取值

@Retention 元注解取值主要來源于 AnnotationRetention 枚舉類

public enum class AnnotationRetention {
    SOURCE,//源代碼時期(SOURCE): 注解不會存儲在輸出class字節(jié)碼中
    BINARY,//編譯時期(BINARY): 注解會存儲出class字節(jié)碼中,但是對反射不可見
    RUNTIME//運行時期(RUNTIME): 注解會存儲出class字節(jié)碼中,也會對反射可見, 默認是RUNTIME
}

5.3 @MustBeDocumented元注解

介紹

該注解比較簡單主要是為了標注一個注解類作為公共API的一部分,并且可以保證該注解在生成的API文檔中存在。

源碼定義

@Target(AnnotationTarget.ANNOTATION_CLASS)//目標對象只能是注解類
public annotation class MustBeDocumented

5.4 @Repeatable元注解

介紹

這個注解決定標注的注解在一個注解在一個代碼元素上可以應(yīng)用兩次或兩次以上。

源碼定義

@Target(AnnotationTarget.ANNOTATION_CLASS)//目標對象只能是注解類
public annotation class Repeatable

5.5 為啥Kotlin去掉了Java中的@Inherited元注解

Java 中的 @Inherited 元注解介紹

Inheried 顧名思義就是繼承的意思,但是這里需要注意并不是表示注解類可以繼承,而是如果一個父類被貼上 @Inherited 元注解標簽,那么它的子類沒有任何注解標簽的話,這個子類就會繼承來自父類的注解。類似下面的例子:

@Inherited
@Retention(RetentionPolicy.RUNTIME)
public @interface TestAnnotation {
}

@TestAnnotation
class Animal {
    //...
}

class Cat extends Animal{//也會擁有來自父類Animal的@TestAnnotation注解
    //...
}

Kotlin 為啥不需要 @Inherited 元注解?

關(guān)于這個問題實際上在 Kotlin 官網(wǎng)的 discuss 中就有人提出了這個問題,具體感興趣的可以去看看:Inherited annotations and other reflections enchancements。

這里大概說下原因,我們都知道在 Java 中,無法找到子類方法是否重寫了父類的方法。因此不能繼承父類方法的注解。然而 Kotlin 目前不需要支持這個 @Inherited 元注解,因為 Kotlin 可以做到,如果反射提供了override 標記而且很容易做到。

6. 注解的使用場景

  • 提供信息給編譯器: 編譯器可以利用注解來處理一些,比如一些警告信息,錯誤等;
  • 編譯階段時處理: 利用注解信息來生成一些代碼,在Kotlin生成代碼非常常見,一些內(nèi)置的注解為了與Java API的互操作性,往往借助注解在編譯階段生成一些額外的代碼;
  • 運行時處理: 某些注解可以在程序運行時,通過反射機制獲取注解信息來處理一些程序邏輯。