kotlin注解

一、声明注解

声明自定义注解可以使用 annotation 关键字实现,最简单形式的注解实例代码如下:

annotation class Marker

上述代码声明一个 Marker 注解,annotation 声明一个注解类型,注解的可见性有 公有的、内部的 和 私有的,不能是保护的。

Marker 注解中不包含任何的成员,这种注解称为标记注解,标记注解属于基本注解。注解也可以有成员属性,通过构造函数初始化成员属性。如下:

annotation class MyAnnotation1(val value: String)

代码中 (val value: String) 是声明注解 MyAnnotation1 的构造函数,构造函数参数类型只能是 基本数据类型、字符串、类类型(KClass)、枚举、数组 和 其他的注解类型。

此外,构造函数 (val value: String) 同时声明了注解 MyAnnotation1 有一个成员属性 value,成员属性的可见性只能是公有的。

注解成员属性也可以有默认值,如下:

annotation class MyAnnotation2(val value: String = "注解信息", val count: Int = 20)

使用这些注解示例代码如下:

@Marker     // 1
class Person {
    // 名字
    @MyAnnotation1(value = "名字")        // 2
    @JvmField
    var name = "Tony"

    // 年龄
    @MyAnnotation2(value = "年龄")        // 3
    var age = 18
}

@Marker     // 4
fun main(args: Array<String>) {
    @Marker     // 5
    @MyAnnotation2(value = "实例化Person", count = 1)      // 6
    val p = Person()
}

默认情况下注解可以修饰任意的代码元素(类、接口、属性、变量、函数 和 数据类型等)。代码第1行、第4行和第5行都使用 @Marker 注解,分别修饰 类、函数 和 变量。

代码第2行是使用 @MyAnnotation1(value=“名字”) 注解修饰 name 成员属性,其中 value = “名字” 是为 value 属性提供数值。代码第3行是使用 MyAnnotation2(value = “年龄”) 注解修饰成员函数,@MyAnnotation2 有两个成员属性,但是只为 value 成员属性赋值,另一个成员属性 count 是使用默认值。代码第6行使用 @MyAnnotation2(value = “实例化Person”, count = 1) 注解修饰变量。

二、使用元注解

上面声明的注解只是最基本形式的注解,对于复杂的注解可以在声明注解时使用元注解。下面在一个自定义注解中使用元注解。在此案例中定义了两个注解。

  • 第一个注解,用来注解类和接口
@MustBeDocumented                                       // 1
@Target(AnnotationTarget.CLASS)                         // 2
@Retention(AnnotationRetention.RUNTIME)                 // 3
annotation class MyAnnotation(val description: String)  // 4

代码第4行声明注解类型 MyAnnotation,其中使用了三个元注解修饰 MyAnnotaion 注解。代码第1行使用 @MustBeDocumented 指定 MyAnnotaion 注解信息可以被文档生成工具读取。代码第2行使用 @Target(AnnotationTarget.CLASS) 指定 MyAnnotaion 注解用于修饰类 和 接口等类型。代码第3行 @Retention(AnnotationRetention.RUNTIME) 指定 MyAnnotaion 注解信息可以在运行时被读取。代码第4行的 description 是 MyAnnotaion 注解的属性。

  • 第二个注解,用来注解类中成员属性和函数
@MustBeDocumented
@Retention(AnnotationRetention.RUNTIME)                 // 1
@Target(
    AnnotationTarget.FUNCTION,
    AnnotationTarget.PROPERTY,
    AnnotationTarget.PROPERTY_GETTER,
    AnnotationTarget.PROPERTY_SETTER
)                                                       // 2
annotation class MemberAnnotation(val type: KClass<*> = Unit::class, val description: String)   // 3

上述代码第3行是声明注解类型 MemberAnnotation,其中也使用三个元注解修饰 MemberAnnotation 注解。代码第1行的 @Retention(AnnotationRetention.RUNTIME) 指定 MemberAnnotation 注解信息可以在运行时被读取。代码第2行 @Target 指定 MemberAnnotation 注解用于修饰类中成员(函数、属性、属性的getter访问器 和 属性的setter访问器)。

代码第3行中还声明 MemberAnnotation 注解的属性是 type 和 description,type 类型是 KClass<*>,默认值是 Unit::class。description 类型是 String,没有设置默认值。

提示:代码第3行的 KClass<> 类型表示 KClass 的泛型, 是泛型通配符,可以是任何类型。多数情况下泛型尖括号中指定的都是某个具体类型,泛型也是为此而设计的。但是有时确实不需要知道具体类型,或者说什么类型都可以,此时可以使用 * 通配所有类型。

  • 使用 MyAnnotation 和 MemberAnnotation 注解的 Student 类
@MyAnnotation(description = "这是一个测试类")  // 1
class Student {
    @MemberAnnotation(type = String::class, description = "名字") // 2
    @get:MemberAnnotation(type = String::class, description = "获得名字") // 3
    var name: String? = null
        private set

    @MemberAnnotation(type = Int::class, description = "年龄")    // 4
    @get:MemberAnnotation(type = Int::class, description = "获得年龄") // 5
    var age: Int = 0
        private set

    @MemberAnnotation(description = "设置姓名和年龄")  // 6
    fun setNameAndAge(name: String, age: Int) {
        this.name = name
        this.age = age
    }

    override fun toString(): String {
        return "Person [name=$name, age=$age]"
    }
}

如果当前类与注解不在同一个包中,则需要将注解引入。代码第1行的 @MyAnnotation 只能在 Student 类声明之前。代码第2行 @MemberAnnotation 注解 name 成员属性,代码第3行 @get:MemberAnnotation 注解 name 成员属性 getter 访问器。代码第4行 @MemberAnnotation 注解 age 成员属性。代码第5行 @get:MemberAnnotation 注解 age 成员属性 getter 访问器。第6行是使用 @MemberAnnotation 注解成员函数。

三、读取运行时注解信息

注解时为工具读取信息而准备的。有些工具可以读取源代码文件中的注解信息;有的可以读取字节码文件中的注解信息;有的可以在运行时读取注解信息。但是读取这些注解信息的代码都是一样的,区别只在于自定义注解中 @Retention 的保留期不同。

读取注解信息所需要的反射 API 是 KClass 类的 findAnnotation 函数。读取运行时 Student 类中注解信息代码如下:

fun main(args: Array<String>) {
    val clz = Student::class        // 1

    // 读取类注解
    val ann = clz.findAnnotation<MyAnnotation>()    // 2
    println("类${clz.simpleName},注解描述:${ann?.description ?: ""}")   // 3

    // 读取成员函数的注解信息
    println("---------- 读取成员函数的注解信息 ----------")
    clz.declaredFunctions.forEach {     // 4
        val ann = it.findAnnotation<MemberAnnotation>()     // 5
        println("函数${it.name},注解描述:${ann?.description ?: ""}")
    }

    // 读取属性的注解信息
    println("---------- 读取属性的注解信息 ----------")
    clz.declaredMemberProperties.forEach {      // 6
        val ann = it.findAnnotation<MemberAnnotation>()     // 7
        println("属性${it.name},注解描述:${ann?.description ?: ""}")
    }
}

运行结果:

Student,注解描述:这是一个测试类
---------- 读取成员函数的注解信息 ----------
函数setNameAndAge,注解描述:设置姓名和年龄
函数toString,注解描述:无
---------- 读取属性的注解信息 ----------
属性age,注解描述:年龄
属性name,注解描述:名字

Process finished with exit code 0

上述代码第1行是创建 Student 类引用,代码第2行使用 findAnnotation 函数查找 Student 类是否有 MyAnnotation。代码第3行中 ann?.description 表达式读取 MyAnnotation 注解中的 description 属性内容。

代码第4行 clz.declaredFunctions 返回当前 Student 类中所有成员函数的集合。代码第5行是查找 Student 成员函数是否有 MemberAnnotation 注解。

代码第6行 clz.declaredMemberProperties 返回当前 Student 类中所有成员的属性集合。代码第7行是查找 Student 成员属性是否有 MemberAnnotation 注解。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

互联网小熊猫

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值