Kotlin 的注解类详解及实例
kotlin 的注解类详解及实例
注解声明
注解是将元数据附加到代码的方法。要声明注解,请将 annotation 修饰符放在类的前面:
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 关键字 ,并将注解添加到其前面:
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 注解来选择目标 。如果有多个适用的目标,则使用以下列表中的第一个适用目标:
- 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 }
感谢阅读,希望能帮助到大家,谢谢大家对本站的支持!