Kotlin註解
註解聲明
註解是將元數據附加到代碼的方法。要聲明註解,請將 annotation{: .keyword } 修飾符放在類的前面:
annotation class Fancy
註解的附加屬性可以通過用元註解標註註解類來指定:
@Target
指定可以用
該註解標註的元素的可能的類型(類、函數、屬性、表達式等);@Retention
指定該註解是否
存儲在編譯後的 class 文件中,以及它在運行時能否通過反射可見
(默認都是 true);@Repeatable
允許
在單個元素上多次使用相同的該註解;@MustBeDocumented
指定
該註解是公有 API 的一部分,並且應該包含在
生成的 API 文檔中顯示的類或方法的簽名中。
@Target(AnnotationTarget.CLASS, AnnotationTarget.FUNCTION,
AnnotationTarget.VALUE_PARAMETER, AnnotationTarget.EXPRESSION)
@Retention(AnnotationRetention.SOURCE)
@MustBeDocumented
annotation class Fancy
用法
@Fancy class Foo {
@Fancy fun baz(@Fancy foo: Int): Int {
return (@Fancy 1)
}
}
如果需要對類的主構造函數進行標註,則需要在構造函數聲明中添加 constructor{: .keyword} 關鍵字
,並將註解添加到其前面:
class Foo @Inject constructor(dependency: MyDependency) {
// ……
}
你也可以標註屬性訪問器:
class Foo {
var x: MyDependency? = null
@Inject set
}
構造函數
註解可以有接受參數的構造函數。
annotation class Special(val why: String)
@Special("example") class Foo {}
允許的參數類型有:
- 對應於 Java 原生類型的類型(Int、 Long等);
- 字符串;
- 類(
Foo::class
); - 枚舉;
- 其他註解;
- 上面已列類型的數組。
註解參數不能有可空類型,因爲 JVM 不支持將 null
作爲
註解屬性的值存儲。
如果註解用作另一個註解的參數,則其名稱不以 @ 字符爲前綴:
annotation class ReplaceWith(val expression: String)
annotation class Deprecated(
val message: String,
val replaceWith: ReplaceWith = ReplaceWith(""))
@Deprecated("This function is deprecated, use === instead", ReplaceWith("this === other"))
如果需要將一個類指定爲註解的參數,請使用 Kotlin 類
(KClass)。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
Lambda 表達式
註解也可以用於 lambda 表達式。它們會被應用於生成 lambda 表達式體的 invoke()
方法上。這對於像 Quasar 這樣的框架很有用,
該框架使用註解進行併發控制。
annotation class Suspendable
val f = @Suspendable { Fiber.sleep(10) }
註解使用處目標
當對屬性或主構造函數參數進行標註時,從相應的 Kotlin 元素
生成的 Java 元素會有多個,因此在生成的 Java 字節碼中該註解有多個可能位置
。如果要指定精確地指定應該如何生成該註解,請使用以下語法:
class Example(@field:Ann val foo, // 標註 Java 字段
@get:Ann val bar, // 標註 Java getter
@param:Ann val quux) // 標註 Java 構造函數參數
可以使用相同的語法來標註整個文件。 要做到這一點,把帶有目標 file
的註解放在
文件的頂層、package 指令之前或者在所有導入之前(如果文件在默認包中的話):
@file:JvmName("Foo")
package org.jetbrains.demo
如果你對同一目標有多個註解,那麼可以這樣來避免目標重複——在目標後面添加方括號
並將所有註解放在方括號內:
class Example {
@set:[Inject VisibleForTesting]
var collaborator: Collaborator
}
支持的使用處目標的完整列表爲:
-
file
-
property
(具有此目標的註解對 Java 不可見) -
field
-
get
(屬性 getter) -
set
(屬性 setter) -
receiver
(擴展函數或屬性的接收者參數) -
param
(構造函數參數) -
setparam
(屬性 setter 參數) -
delegate
(爲委託屬性存儲其委託實例的字段)
要標註擴展函數的接收者參數,請使用以下語法:
fun @receiver:Fancy String.myExtension() { }
如果不指定使用處目標,則根據正在使用的註解的 [@Target](https://github.com/Target "@Target")
註解來選擇目標
。如果有多個適用的目標,則使用以下列表中的第一個適用目標:
-
param
-
property
-
field
Java 註解
Java 註解與 Kotlin 100% 兼容:
import org.junit.Test
import org.junit.Assert.*
import org.junit.Rule
import org.junit.rules.*
class Tests {
// 將 @Rule 註解應用於屬性 getter
@get:Rule val tempFolder = TemporaryFolder()
@Test fun simple() {
val f = tempFolder.newFile()
assertEquals(42, getTheAnswer())
}
}
因爲 Java 編寫的註解沒有定義參數順序,所以不能使用常規函數調用
語法來傳遞參數。相反,你需要使用命名參數語法。
// Java
public @interface Ann {
int intValue();
String stringValue();
}
// Kotlin
@Ann(intValue = 1, stringValue = "abc") class C
就像在 Java 中一樣,一個特殊的情況是 value
參數;它的值無需顯式名稱指定。
// Java
public @interface AnnWithValue {
String value();
}
// Kotlin
@AnnWithValue("abc") class C
如果 Java 中的 value
參數具有數組類型,它會成爲 Kotlin 中的一個 vararg
參數:
// Java
public @interface AnnWithArrayValue {
String[] value();
}
// Kotlin
@AnnWithArrayValue("abc", "foo", "bar") class C
對於具有數組類型的其他參數,你需要顯式使用 arrayOf
:
// Java
public @interface AnnWithArrayMethod {
String[] names();
}
// Kotlin
@AnnWithArrayMethod(names = arrayOf("abc", "foo", "bar")) class C
註解實例的值會作爲屬性暴露給 Kotlin 代碼。
// Java
public @interface Ann {
int value();
}
// Kotlin
fun foo(ann: Ann) {
val i = ann.value
}