注解
Kotlin官网:Other-Annotations
注解声明
注解用来给代码附加元数据,在类前加annotation
关键字声明为注解:
annotation class Fancy
使用元注解定义注解的性质:
- @Target:定义注解可用的目标类型,例如类、函数、属性、表达式等等;
- @Retention:定义注解是否存储于编译类文件中,运行时是否可见,默认两者皆为true;
- @Repeatable:定义是否可在同一元素上多次使用;
- @MustBeDocumented:定义注解是否是公共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关键字就不能省略,将注解加在constructor关键字前:
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不支持将空值存储为注解参数。
当注解作为其他注解的参数时,作为参数的注解不加”@”:
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()方法上:
annotation class Suspendable
val f = @Suspendable { Fiber.sleep(10) }
使用侧目标的注解
一个Kotlin元素可能会生成多个对应的Java元素,添加注解时想指定使用侧目标Java元素:
class Example(@field:Ann val foo, // annotate Java field
@get:Ann val bar, // annotate Java getter
@param:Ann val quux) // annotate Java constructor parameter
也可以给Kotlin文件整体加注解,文件的注解写在包声明之前,如果在默认包中没有包声明则写在所有导包之前:
@file:JvmName("Foo")
package org.jetbrains.demo
如果一个目标上有多个注解,无需多次重复,可以写到一个中括号中:
class Example {
@set:[Inject VisibleForTesting]
var collaborator: Collaborator
}
所有支持的使用侧目标:
- file文件;
- property属性(Java中不可见)
- get(属性的getter);
- set(属性的setter);
- receiver接收者(扩展函数或属性的接收者);
- param参数(构造器参数);
- setpara(尚需经setter参数);
- delegate委托(存储委托属性的委托实例的字段)。
给扩展函数的接收者加注解:
fun @receiver:Fancy String.myExtension() { }
如果没有定义使用侧目标会默认使用@Target注解中的,如果有多个符合,按照以下优先级:
- param参数;
- property属性;
- field字段。
Java注解
Kotlin兼容Java注解:
import org.junit.Test
import org.junit.Assert.*
import org.junit.Rule
import org.junit.rules.*
class Tests {
// apply @Rule annotation to property getter
@get:Rule val tempFolder = TemporaryFolder()
@Test fun simple() {
val f = tempFolder.newFile()
assertEquals(42, getTheAnswer())
}
}
由于Java中多个参数的注解参数顺序是不定的,在Kotlin中使用时要指定参数名:
// Java
public @interface Ann {
int intValue();
String stringValue();
}
// Kotlin
@Ann(intValue = 1, stringValue = "abc") class C
Java中的特殊属性value无需声明属性名的特性Kotlin也支持:
// 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
其他的Java数组型属性对应Kotlin中的数组,使用arrayOf函数,或从Kotlin1.2后支持数组字面值:
// Java
public @interface AnnWithArrayMethod {
String[] names();
}
// Kotlin 1.2+:
@AnnWithArrayMethod(names = ["abc", "foo", "bar"])
class C
// Older Kotlin versions:
@AnnWithArrayMethod(names = arrayOf("abc", "foo", "bar"))
class D
获取注解的属性
注解中的属性值在Kotlin中作为属性处理:
// Java
public @interface Ann {
int value();
}
// Kotlin
fun foo(ann: Ann) {
val i = ann.value
}