一文了解 kotlin 中的注解

705 阅读3分钟

在 kotlin 中,我们会碰到许许多多的注解,比如@Deprecated@JvmStatic 等等。不同于 Java,kotlin 注解由 annotation class 声明。

@Target(AnnotationTarget.CLASS, AnnotationTarget.FUNCTION,
        AnnotationTarget.TYPE_PARAMETER, AnnotationTarget.VALUE_PARAMETER,
        AnnotationTarget.EXPRESSION)
@Retention(AnnotationRetention.SOURCE)
@MustBeDocumented
annotation class MyAnnotation

如上面示例所示,我们定义了一个 MyAnnotation 的注解。可以看到定义的注解上也有注解,它们被称为元注解,是用来声明自定义注解的属性的。

元注解

元注解有四个,分别是:@Target@Retention@Repeatable@MustBeDocumented。下面分别来介绍:

@Target

@Target 用于指定哪些元素种类可以用该注解(例如类、函数、属性和表达式);所有的元素种类在 AnnotationTarget 枚举类中声明,用于指定注解可以应用的目标元素种类。以下是对其各种目标类型的总结:

  1. 类相关:

    • AnnotationTarget.CLASS:可以应用于类、接口、对象以及注解类。
    • AnnotationTarget.ANNOTATION_CLASS:仅应用于注解类。
  2. 类型参数相关:

    • AnnotationTarget.TYPE_PARAMETER:应用于泛型类型参数。
  3. 属性相关:

    • AnnotationTarget.PROPERTY:应用于属性整体,包括其 getter 和 setter。
    • AnnotationTarget.PROPERTY_GETTER:仅应用于属性的 getter。
    • AnnotationTarget.PROPERTY_SETTER:仅应用于属性的 setter。
  4. 字段相关:

    • AnnotationTarget.FIELD:包括属性的 backing field 和普通字段。
  5. 变量相关:

    • AnnotationTarget.LOCAL_VARIABLE:应用于局部变量。
    • AnnotationTarget.VALUE_PARAMETER:应用于函数或构造函数的参数。
  6. 函数相关:

    • AnnotationTarget.FUNCTION:应用于普通函数,不包括构造函数。
    • AnnotationTarget.CONSTRUCTOR:仅应用于构造函数。
  7. 其他类型:

    • AnnotationTarget.TYPE:应用于类型使用处。
    • AnnotationTarget.EXPRESSION:应用于任何表达式。
    • AnnotationTarget.FILE:应用于文件级别。
    • AnnotationTarget.TYPEALIAS:自 Kotlin 1.1 起,可应用于类型别名。

@Retention

@Retention 用来指定注解信息的保留策略,有三种情况分别是:

  • AnnotationRetention.SOURCE:注解仅在源代码中有效,编译后会被丢弃。
  • AnnotationRetention.BINARY: 注解会被存储在编译后的二进制输出(字节码文件)中,但在运行时通过反射无法访问到。
  • AnnotationRetention.RUNTIME:这是默认的保留策略。在此策略下,注解不仅会被存储在编译后的字节码中,而且在运行时也可以通过反射获取到。

@Repeatable

@Repeatable 用来表明当前的注解可以在单个元素上多次使用

@MustBeDocumented

@MustBeDocumented 表明当前注解是公共 API 的一部分,并应包含在生成的 API 文档中显示的类或方法签名中

注解的参数

我们还可以为注解设置参数,代码示例如下:

@Target(AnnotationTarget.CLASS, AnnotationTarget.FUNCTION,
    AnnotationTarget.TYPE_PARAMETER, AnnotationTarget.VALUE_PARAMETER,
    AnnotationTarget.EXPRESSION)
@Retention(AnnotationRetention.SOURCE)
@MustBeDocumented
annotation class MyAnnotation(val str: String, // 支持java的基本数据类型和String
                              val clazz: KClass<*>, // 支持class对象,但不支持其他对象 
                              val paramAnnotation: ParamAnnotation, // 支持其他注解,注意不能带 @ 
                              val array: Array<String>) // 支持数组,但是不支持集合
                              
@Target(AnnotationTarget.CLASS, AnnotationTarget.FUNCTION,
    AnnotationTarget.TYPE_PARAMETER, AnnotationTarget.VALUE_PARAMETER,
    AnnotationTarget.EXPRESSION)
@Retention(AnnotationRetention.SOURCE)
@MustBeDocumented
annotation class ParamAnnotation(val name: String)                              

从上面的示例,我们可以看到注解的参数支持java的基本数据类型和String类型;支持class对象,但不支持其他对象类型;支持其他注解;支持数组类型,但是不支持集合类型。

注解的使用

一般来说,注解的使用非常简单,只需要在支持使用注解的地方声明注解就可以了。但是对于一些特殊类,比如说为 data class 的get方法和构造函数设置注解。代码示例如下:

annotation class MyAnnotation() // 注意当前注解的 @Target 必须支持声明的位置

data class Example(@field:MyAnnotation val foo: String,    // 注解字段
              @get:MyAnnotation val bar: String,      // 注解 getter
              @param:MyAnnotation val quux: String)   // 注解构造函数参数

如果我们需要获取注解的值,可以使用 findAnnotations 方法。

参考