一、应用注解
在Kotlin中使用注解的方法和Java一样。要应用一个注解,以**@
字符作为(注解)名字的前缀**,并放在要注解的声明最前面。
注解只能拥有如下类型的参数:基本数据类型、字符串、枚举、类引用、其他的注解类,以及前面这些类型的数组。
指定注解实参的语法与Java有些微小的差别:
- 要把一个类指定为注解实参,在类名后加上**
::class: @MyAnnotation(MyClass::class)
**。 - 要把另一个注解指定为一个实参,去掉注解名称前面的
@
。 - 要把一个数组指定为一个实参,使用**
arrayOf
函数**:@RequestMapping(path = arrayOf("/foo", "/bar"))
。
注解实参需要在编译期就是已知的,所以不能引用任意的属性作为实参。要把属性当作注解实参使用,需要用**const
修饰符标记它,来告知编译器这个属性是编译期变量**。
const val TEST_TIMEOUT = 100L
@Test(timeout = TEST_TIMEOUT) fun testMethod() { ... }
二、注解目标
使用点目标声明被用来说明要注解的元素。使用点目标被放在**@
符号和注解名称之间,并用冒号和注解名称隔开**,如图1。
class HasTempFolder {
// 注解的是getter,而不是属性。
@get: Rule
val folder = TemporaryFolder()
@Test
fun testUsingTempFolder() {
// ...
}
}
注:上述代码需使用JUnit框架。
使用Java中声明的注解来注解一个属性,它会被默认地应用到相应的字段上。Kotlin也可以让你声明被直接对应到属性上的注解。
Kotlin支持的使用点目标的完整列表如下:
property
:Java的注解不能应用这种使用点目标。field
:为属性生成的字段get
:属性的getter
set
: 属性的setter
receiver
: 扩展函数或者扩展属性的接受者参数。param
: 构造方法的参数setparam
: **属性setter
**的参数delegate
: 为委托属性存储委托实例的字段file
: 包含在文件中声明的顶层函数和属性的类
注意:任何应用到
file
目标的注解都必须放在文件的顶层,放在**package
指令之前**。
用注解控制JavaAPI Kotlin提供了各种注解来控制Kotlin编写的声明如何编译成字节码并暴露给Java调用者。
@JvmName
将改变由**Kotlin
生成的Java方法或字段的名称**@JvmStatic
能被用在对象声明或者伴生对象的方法上,把它们暴露成**Java
的静态方法**@JvmOverloads
指导Kotlin编译器为带默认参数值的函数生成多个重载(函数)@JvmField
可以应用于一个属性,把这个属性暴露成一个没有访问器的公有Java字段
三、声明注解
annotation class JsonExclude
语法看起来和常规类的声明很像,只是在class
关键字之前加上了**annotation
修饰符**。因为注解类只是用来定义关联到声明和表达式的元数据的结构,它们不能包含**任何代码
**。因此编译器禁止为一个注解类指定类主体。
四、元注解:控制如何处理一个注解
和Java一样,一个Kotlin注解类自己也可以被注解。可以应用到注解类上的注解被称作元注解。
标准库定义的元注解中最常见的就是@Target。JKid中@JsonExclude和@JsonName的声明使用它为这些注解指定有效的目标。
@Target(AnnotationTarget.PRIPERTY)
annotation class JsonExclude
注:@JsonExclude 是 JKid库中的方法
@Target
元注解说明了注解可以被应用的元素类型。如果不使用它,所有的声明都可以应用这个注解。这并不是JKid想要的,因为它只需要处理属性的注解。
五、使用泛型类做注解参数
@CustomSerializer
注解接受一个自定义序列化器类的引用作为实参。
interface ValueSerializer<T> {
fun toJsonValue(value: T): Any?
fun fromJsonValue(jsonValue: Any?): T
}
data class PersonAnnotation(
val name: String,
@CustomSerializer(DateSerializer::class) val birthDate: Date
)
// @CustomSerializer底层源码
annotation class CustomSerializer(
val serializerClass: KClass<out ValueSerializer<*>>
)