Kotlin 的注解类详解及实例
Kotlin的注解类详解及实例
注解声明
注解是将元数据附加到代码的方法。要声明注解,请将annotation修饰符放在类的前面:
annotationclassFancy
注解的附加属性可以通过用元注解标注注解类来指定:
- @Target指定可以用该注解标注的元素的可能的类型(类、函数、属性、表达式等);
- @Retention指定该注解是否存储在编译后的class文件中,以及它在运行时能否通过反射可见(默认都是true);
- @Repeatable允许在单个元素上多次使用相同的该注解;
- @MustBeDocumented指定该注解是公有API的一部分,并且应该包含在生成的API文档中显示的类或方法的签名中。
@Target(AnnotationTarget.CLASS,AnnotationTarget.FUNCTION,
AnnotationTarget.VALUE_PARAMETER,AnnotationTarget.EXPRESSION)
@Retention(AnnotationRetention.SOURCE)
@MustBeDocumented
annotationclassFancy
用法
@FancyclassFoo{ @Fancyfunbaz(@Fancyfoo:Int):Int{ return(@Fancy1) } }
如果需要对类的主构造函数进行标注,则需要在构造函数声明中添加constructor关键字,并将注解添加到其前面:
classFoo@Injectconstructor(dependency:MyDependency){ //…… }
你也可以标注属性访问器:
classFoo{ varx:MyDependency?=null @Injectset }
构造函数
注解可以有接受参数的构造函数。
annotationclassSpecial(valwhy:String) @Special("example")classFoo{}
允许的参数类型有:
- 对应于Java原生类型的类型(Int、Long等);
- 字符串;
- 类(Foo::class);
- 枚举;
- 其他注解;
- 上面已列类型的数组。
注解参数不能有可空类型,因为JVM不支持将null作为注解属性的值存储。
如果注解用作另一个注解的参数,则其名称不以@字符为前缀:
annotationclassReplaceWith(valexpression:String) annotationclassDeprecated( valmessage:String, valreplaceWith:ReplaceWith=ReplaceWith("")) @Deprecated("Thisfunctionisdeprecated,use===instead",ReplaceWith("this===other"))
如果需要将一个类指定为注解的参数,请使用Kotlin类(KClass)。Kotlin编译器会自动将其转换为Java类,以便Java代码能够正常看到该注解和参数。
importkotlin.reflect.KClass annotationclassAnn(valarg1:KClass<*>,valarg2:KClass) @Ann(String::class,Int::class)classMyClass
Lambda表达式
注解也可以用于lambda表达式。它们会被应用于生成lambda表达式体的invoke()方法上。这对于像Quasar这样的框架很有用, 该框架使用注解进行并发控制。
annotationclassSuspendable valf=@Suspendable{Fiber.sleep(10)}
注解使用处目标
当对属性或主构造函数参数进行标注时,从相应的Kotlin元素生成的Java元素会有多个,因此在生成的Java字节码中该注解有多个可能位置。如果要指定精确地指定应该如何生成该注解,请使用以下语法:
classExample(@field:Annvalfoo,//标注Java字段 @get:Annvalbar,//标注Javagetter @param:Annvalquux)//标注Java构造函数参数
可以使用相同的语法来标注整个文件。要做到这一点,把带有目标file的注解放在文件的顶层、package指令之前或者在所有导入之前(如果文件在默认包中的话):
@file:JvmName("Foo") packageorg.jetbrains.demo
如果你对同一目标有多个注解,那么可以这样来避免目标重复——在目标后面添加方括号并将所有注解放在方括号内:
classExample{ @set:[InjectVisibleForTesting] varcollaborator:Collaborator }
支持的使用处目标的完整列表为:
- file
- property(具有此目标的注解对Java不可见)
- field
- get(属性getter)
- set(属性setter)
- receiver(扩展函数或属性的接收者参数)
- param(构造函数参数)
- setparam(属性setter参数)
- delegate(为委托属性存储其委托实例的字段)
要标注扩展函数的接收者参数,请使用以下语法:
fun@receiver:FancyString.myExtension(){}
如果不指定使用处目标,则根据正在使用的注解的@Target注解来选择目标。如果有多个适用的目标,则使用以下列表中的第一个适用目标:
- param
- property
- field
Java注解
Java注解与Kotlin100%兼容:
importorg.junit.Test importorg.junit.Assert.* importorg.junit.Rule importorg.junit.rules.* classTests{ //将@Rule注解应用于属性getter @get:RulevaltempFolder=TemporaryFolder() @Testfunsimple(){ valf=tempFolder.newFile() assertEquals(42,getTheAnswer()) } }
因为Java编写的注解没有定义参数顺序,所以不能使用常规函数调用语法来传递参数。相反,你需要使用命名参数语法。
//Java public@interfaceAnn{ intintValue(); StringstringValue(); } //Kotlin @Ann(intValue=1,stringValue="abc")classC
就像在Java中一样,一个特殊的情况是value参数;它的值无需显式名称指定。
//Java public@interfaceAnnWithValue{ Stringvalue(); } //Kotlin @AnnWithValue("abc")classC
如果Java中的value参数具有数组类型,它会成为Kotlin中的一个vararg参数:
//Java public@interfaceAnnWithArrayValue{ String[]value(); } //Kotlin @AnnWithArrayValue("abc","foo","bar")classC
对于具有数组类型的其他参数,你需要显式使用arrayOf:
//Java public@interfaceAnnWithArrayMethod{ String[]names(); } //Kotlin @AnnWithArrayMethod(names=arrayOf("abc","foo","bar"))classC
注解实例的值会作为属性暴露给Kotlin代码。
//Java public@interfaceAnn{ intvalue(); } //Kotlin funfoo(ann:Ann){ vali=ann.value }
感谢阅读,希望能帮助到大家,谢谢大家对本站的支持!