文章参考
1、概念
注解可以对 类、函数、函数参数、属性等 做标注
注解信息可用于 源码级、编译期、运行时
示例
@Retention(AnnotationRetention.RUNTIME) //作用于运行时
@Target(AnnotationTarget.CLASS) //限定作用于类
annotation class Api(val url: String)
/*** @Retention 保留期 ***/
//AnnotationRetention.SOURCE 源码级: 注解只在源码阶段保留,在编译器进行编译时它将被丢弃忽视。 常用于代码检测。
//AnnotationRetention.BINARY 编译期: 注解被编译到二进制文件,但不会被加载到 JVM 中。 反射不可见。
//AnnotationRetention.RUNTIME 运行时: 注解被编译到二进制文件,它会被加载进入到 JVM 中,所以在程序运行时可以获取到它们。默认值。可用于运行时反射获取注解信息。
//SOURCE < BINARY < RUNTIME
//标注为运行时,则在编译期、源码级均可见
//标注为编译期,则在源码级可见
/*** @Target 作用域 ***/
//AnnotationTarget.CLASS 可以给一个类型进行注解,类、接口、对象、甚至注解类本身
//AnnotationTarget.FUNCTION 方法、函数(不包括构造函数)
//AnnotationTarget.CONSTRUCTOR 构造函数
//AnnotationTarget.VALUE_PARAMETER 方法、构造函数的参数
//AnnotationTarget.ANNOTATION_CLASS 可以给一个注解类进行注解
//......
/*** 注解类中的参数 (对应次示例中的val url: String) ***/
//仅支持以下类型及其数组(都是在编译器就可以确定的类型, 自定义类型就不行)
//基本类型
//KClass
//枚举
//其他注解
/*** 指定注解作用域 ***/
//file 注解整个文件时指定
//property (计算)属性(该注解对 Java 不可见)
//field 字段
//get 属性 getter
//set 属性 setter
//receiver 扩展函数或属性的接收者
//param 构造函数参数
//setparam 属性 setter 参数
//delegate 委托属性存储其委托实例的字段
/*** @file ***/
@file:FileAnn("对整个file注解,而不是在package上面就是package的注解")
package com.example.kotlinlearning_zlz.zhujie10
@Retention(AnnotationRetention.RUNTIME)
@Target(AnnotationTarget.FILE)
annotation class FileAnn(val message: String)
/*** @receiver ***/
@Retention(AnnotationRetention.RUNTIME)
@Target(AnnotationTarget.FUNCTION, AnnotationTarget.VALUE_PARAMETER)
annotation class ReceiverFunAnn(val message: String)
@Retention(AnnotationRetention.RUNTIME)
@Target(AnnotationTarget.PROPERTY)
annotation class ReceiverPropertyAnn(val message: String)
fun @receiver:ReceiverFunAnn("这是一个扩展方法注解") Int.display() {
println(this)
}
val @receiver:ReceiverFunAnn("这是一个扩展属性注解") String.firstChar: Char get() = this[0]
/*** @get @set ***/
@Retention(AnnotationRetention.RUNTIME)
@Target(AnnotationTarget.PROPERTY_GETTER)
annotation class GetAnn(val message: String)
@Retention(AnnotationRetention.RUNTIME)
@Target(AnnotationTarget.PROPERTY_SETTER)
annotation class SetAnn(val message: String)
class Test(
@get:GetAnn("属性getter注解")
val str: String? = null,
@set:SetAnn("属性setter注解")
var num: Int = 0
)
2、常见内置注解
kotlin.annotation.* | 用于标注注解的注解 |
---|---|
kotlin.* | 标准库的一些通用用途的注解 |
kotlin.jvm.* | 用于于Java虚拟机交互的注解 |
2.1、标注注解的注解 kotlin.annotation.*
2.2、标准库通用注解 kotlin.*
Metadata | Kotlin 反射的信息通过该注解附带在元素上 |
---|---|
UnsafeVariance | 泛型用来破除型变限制 |
Suppress | 用来去除编译器警告,警告类型作为参数传入 |
2.3、Java虚拟机相关注解 kotlin.jvm.*
常用
JvmFiled | 生成Java Field (不包含setter和getter) |
---|---|
JvmName | 指定类、函数等生成的Jvm名字(比如,给方法指定一个java不支持的名字,则java便访问不到) |
JvmOverloads | 函数默认参数生成函数重载 |
JvmStatic | 生成静态成员 |
Synchronized | 标记函数为同步函数 |
Throws | 标记函数抛出的异常类型 |
Volatile | 生成volatile的Field |
JvmOverloads
@JvmOverloads
fun foo(a: Int, b: Int = 0, c: String = "default") {
// 方法体
}
在这个示例中,使用了 @JvmOverloads 注解来自动生成三个重载方法:
foo(a: Int)
foo(a: Int, b: Int)
foo(a: Int, b: Int, c: String)
这些重载方法可以在 Java 代码中使用,以便在某些情况下忽略一些参数。
Synchronized
@Synchronized
fun getData(){
}
Throws
@Throws(IOException::class)
fun getData(){
throw IOException("这是一个测试Exception")
}
Volatile
在多线程编程中,由于多个线程可能同时访问同一个变量,因此需要确保这些线程之间对变量的访问是同步的。
通常,可以使用锁或其他同步机制来确保线程安全性。
而 @Volatile 注解则提供了一种简单的方式来标记易变变量,以告知编译器和运行时系统需要进行一些特殊的处理。
当一个属性被标记为 @Volatile 后,编译器会生成与之关联的一些特殊指令,以确保对该属性的访问是线程安全的。
在读取或写入该属性的值时,会使用一些特殊的机器指令,以确保不会发生多线程并发访问的问题。
但是需要注意的是,@Volatile 并不能完全解决所有的线程安全问题,
特别是在多个线程同时访问同一个对象时,仍然需要使用其他的同步机制来确保线程安全。
JvmMultifileClass
/*** KotlinAnn1.kt ***/
@file:JvmName("KAnn")
@file:JvmMultifileClass
package com.example.kotlinlearning_zlz.zhujie10.ann
fun test1() {
println("这是 KotlinAnn 1")
}
/*** KotlinAnn2.kt ***/
@file:JvmName("KAnn")
@file:JvmMultifileClass
package com.example.kotlinlearning_zlz.zhujie10.ann
fun test2() {
println("这是 KotlinAnn 2")
}
/*** KT.kt ***/
package com.example.kotlinlearning_zlz.zhujie10.ann
fun main(){
test1()
test2()
}
KotlinAnn1.kt和KotlinAnn2.kt生成时会合并为一个KAnn.kt