前言
函数的调用需要知道函数所在的类,函数的入参个数和参数类型,注解和反射可以跳过这个限制,注解和反射可以编写事先未知的任意类代码。注解可以为类库赋予特定的语义,反射可以在运行时分析类的结构。
注解的声明与使用
注解允许你把额外的元数据关联到一个声明上,然后通过反射在运行时对元数据进行提取并使用。
要应用一个注解,以字符@作为名字前缀,放在注解前面。
可以给注解提供实参
注意:
注解的实参类型可以是基本类型、字符串、枚举、类引用、其他的注解类、数组等,在java中声明的注解类,命名为value的形参按需自动转换成的可变长度的形参,所以可以不用arrayOf函数就可以提供多个实参。
说明 | 表达式 |
把一个类指定为注解实参 | @CustomAnnotation(MineClass::class) |
另一个注解指定为实参 | 去掉注解的@,例如:ReplaceWith作为注解实参时,未加@前缀 |
把一个数组指定为实参 | @RequestMapping(path=arrayof(“/foo”,“/bar”)) |
注解实参需要编译期确定,所以作为注解实参的属性需要使用const修饰,声明在文件的顶层或者object之中。
注解目标
说明元素中那些需要注解十分必要,因为kotlin源代码中的单个声明会对应成多个java声明元素。
使用点目标声明被用来说明要注解的元素,而在java中只需要对字段或者函数添加@Rule注解就可以。
- @get: 使用点目标
- Rule:注解名称
Kotlin 支持的完整使用点目标完整列表
使用点目标 | 介绍 |
property | java的注解下不能应用 |
field | 字段 |
get | 属性getter |
set | 属性setter |
receiver | 接收者参数属性 |
param | 构造方法属性 |
setparam | 属性setter的参数 |
delegate | 委托属性存储委托实例的字段 |
file | 文件中声明的顶层函数和属性的类 |
kotlin中允许对任意的表达式应用注解
Tips:用注解可以控制javaApi的生成
注解 | 解释 |
@volatile | 充当java关键字volatile |
@strictfp | 充当java关键字strictfp |
@JvmName | 改变由kotlin生成的java方法或字段的名称 |
@JvmStatic | 把对象声明或者伴生对象的方法上,暴露成java static静态方法 |
@JvmOverloads | 为带默认参数生成多个重载 |
@JvmField | 应用于属性,暴露成没有访问器public 字段 |
声明注解
注解类没有类主体,编译器也禁止。注解类用来关联到声明和表达式的元数据的结构,在java中声明同样的结构
java中value在kotlin和java中均会被特殊对待。当你应用一个注解时,需要提供除value以外所有指定特性的显示名称.而kotli’n中不需要这么做。和普通构造函数一样用法。如果将java中声明的注解应用到kotlin中,必须对除value以外的所有实参使用命名实参法
//Target.java
元注解:控制如何处理一个注解
元注解:可以应用到注解类上的注解被称作元注解
@Target元注解说明注解可以被应用的元素类型,AnnotationTarget 枚举值列出了可以应用注解的全部可能的目标,如果需要也可以同时声明多个AnnotationTarget目标
如何定义自己的元注解:ANNOTATION_CLASS
注意: PROPERTY注解只在kotlin中可用,如果java中要可用需要同时声明
@Target(AnnotationTarget.FIELD,AnnotationTarget.PROPERTY),对于@Retention注解来声明注解是否会存储到.class文件,运行时是否可以通过反射类访问它,在java中会在.class保留但是无法运行时获取,在kotlin中默认为在.class中存储注解信息,在Runtime保留注解。
使用类作为注解参数
使用场景就是在对一个嵌套类进行反序列化时候,定制使用那个类型实参来进行赋值
注解的声明
注意这里的泛型修饰符out的用法,表示保留子类型的关系。即协变,Kclass可以接收的类型包括Any即Any衍生出来的任何子类型都可以作为Kclass的泛型类型。如果不使用out进行修饰的话,则只能传递Any作为Kclass的泛型类型。
使用泛型类做注解
之后调用时候需要保证serializerClass调用时输入的实参需要实现ValueSerializer接口类
out修饰符,表示接收任何实现了ValueSerializer接口,不只是ValueSerializer::class
ValueSerializer<*>中的 * ,可以序列化任何值
这里提供一个通用的写法对于需要用注解类作为实参传递的注解类:
总结
- java中应用注解语法和kotlin几乎一摸一样
- kotlin让注解的目标范围比java更广,包括了文件和表达式
- 一个注解类的参数可以是基本类型、字符串、枚举、类引用、其他注解类实例、或者数据
- 使用点目标来处理kotlin这种一个声明产生多个字节码元素情况。var a=1 对应java中三种字节码元素。
- 注解类声明拥有一个主构造没有类主体构造方法中所有参数都被标示成val属性
- 元注解用来指定使用点目标、保留期模式、和其他注解的特性
引用
Kotlin实战第十章,注解部分