Kotlin-Annotations详解

在Kotlin中,@注解(Annotations)是用于为代码提供元数据的一种机制。这些元数据可以被编译器、IDE(集成开发环境)或其他工具使用,以生成代码、执行编译时检查或提供运行时信息。

注解通常被用于类、方法、属性、构造函数、参数等

自定义注解

可以使用annotation关键字自定义自己的注解

自定义注解可以包含属性(也称为注解参数),这些属性在注解使用时被赋值

Kotlin 复制代码
annotation class HelloAnnotation(val value: String)

自定义注解的用途非常广泛,例如,它们可以用于标记测试方法、提供配置信息、指示代码生成等

使用自定义注解

Kotlin 复制代码
@HelloAnnotation("hello Annotation")
fun hello(){

}

反射注解

在运行时,可以通过反射(Reflection)读取函数注解信息

反射允许你检查类、方法、属性等上的注解,并读取它们的属性值

Kotlin 复制代码
    val function:KFunction<Unit> = ::hello
    val annotations:List<Annotation> = function.annotations
    for (annotation:Annotation in annotations) {
        if (annotation is HelloAnnotation) {
            println("Annotation: ${annotation.value}") //Annotation: hello Annotation
        }
    }

上面代码运行结果:

Annotation: hello Annotation

元注解

元注解(meta-annotations)是用于修饰其他注解的注解。它们定义了注解的行为和特性

常见的元注解包括:

  1. @Target
    • 指定注解可以应用的Kotlin元素类型,如类、方法、属性、参数等。
    • 如果不指定@Target,则注解可以应用于任何元素。
  2. @Retention
    • 指定注解在何时可用,即注解的生命周期。
    • AnnotationRetention.SOURCE:注解仅在源代码中保留,在编译时被丢弃。
    • AnnotationRetention.BINARY(默认值):注解在编译后的字节码中保留,但在运行时不可通过反射访问。
    • AnnotationRetention.RUNTIME:注解在运行时仍然可用,可以通过反射访问。
  3. @Repeatable
    • 允许同一个注解在同一个元素上被多次使用。
    • 要使注解可重复,你需要定义一个包含该注解类型的数组作为值的容器注解。
Kotlin 复制代码
@Target(AnnotationTarget.FUNCTION, AnnotationTarget.PROPERTY)
@Retention(AnnotationRetention.RUNTIME)
annotation class HelloAnnotation(val value: String)

预定义注解

Kotlin 继承了Java的一些预定义注解,同时也有自己的一些预定义注解。以下是一些常见的预定义注解:

  1. @Deprecated:标记某个类、方法或属性已过时。你可以通过其messagereplaceWith参数来提供更多信息。

  2. @JvmOverloads:用于Kotlin函数,使其生成所有重载的Java方法(带有默认参数的函数)。

  3. @JvmStatic:用于Kotlin伴生对象的成员,使其作为Java静态方法或字段暴露。

  4. @JvmName:指定生成的Java字节码中元素的名称。

  5. @JvmMultifileClass:用于Kotlin的多文件类。

  6. @JvmField:指示Kotlin属性应该直接暴露为Java字段,而不是通过getter和setter。

  7. @file:JvmName:在文件顶部使用,为文件生成的所有类指定一个公共的Java类名。

    Kotlin 复制代码
    // @file:JvmName在文件最顶部使用
    @file:JvmName("Hello")
Kotlin 复制代码
// Hello.kt
package learnAnnotation

fun hello(string: String):String {
    return "Hello, $string"
}

上面是一个标准的kotlin文件

现在我们看看它实际在kotlin编译器中的样纸

java 复制代码
package learnAnnotation;

import kotlin.Metadata;
import kotlin.jvm.internal.Intrinsics;
import org.jetbrains.annotations.NotNull;

@Metadata(
   mv = {2, 0, 0},
   k = 2,
   xi = 48,
   d1 = {"\u0000\n\n\u0000\n\u0002\u0010\u000e\n\u0002\b\u0002\u001a\u000e\u0010\u0000\u001a\u00020\u00012\u0006\u0010\u0002\u001a\u00020\u0001¨\u0006\u0003"},
   d2 = {"hello", "", "string", "learnKotlin"}
)
public final class HelloKt {
   @NotNull
   public static final String hello(@NotNull String string) {
      Intrinsics.checkNotNullParameter(string, "string");
      return "Hello, " + string;
   }
}

默认情况下,Kotlin编译器会为Hello.kt文件创建一个HelloKt类

比如我们直接在java文件中调用该函数时

java 复制代码
//Hi.java
package learnAnnotation;

public class Hi {
    public static void main(String[] args){
        System.out.println(HelloKt.hello("Annotation"));// Hello, Annotation
    }
}

如果不加Kt后缀:

如果这样的命名方式不符合你的调用习惯

这时候@file:JvmName就派上用场了,我们只需要将@file:JvmName放在文件最顶部即可

Kotlin 复制代码
// Hello.kt
// @file:JvmName在文件最顶部使用
@file:JvmName("Hello")

package learnAnnotation

fun hello(string: String):String {
    return "Hello, $string"
}

现在我们重新看下它的字节码

Kotlin 复制代码
package learnAnnotation;

import kotlin.Metadata;
import kotlin.jvm.JvmName;
import kotlin.jvm.internal.Intrinsics;
import org.jetbrains.annotations.NotNull;

@Metadata(
   mv = {2, 0, 0},
   k = 2,
   xi = 48,
   d1 = {"\u0000\n\n\u0000\n\u0002\u0010\u000e\n\u0002\b\u0002\u001a\u000e\u0010\u0000\u001a\u00020\u00012\u0006\u0010\u0002\u001a\u00020\u0001¨\u0006\u0003"},
   d2 = {"hello", "", "string", "learnKotlin"}
)
@JvmName(
   name = "Hello"
)
public final class Hello {
   @NotNull
   public static final String hello(@NotNull String string) {
      Intrinsics.checkNotNullParameter(string, "string");
      return "Hello, " + string;
   }
}

已经被修改成了我们想要的样子

然后java中编译器的错误提示没有了

本例的完整代码

Kotlin 复制代码
//main.kt
package learnAnnotation

import kotlin.reflect.KFunction

fun main(args: Array<String>) {
    val function:KFunction<Unit> = ::hello
    val annotations:List<Annotation> = function.annotations
    for (annotation:Annotation in annotations) {
        if (annotation is HelloAnnotation) {
            println("Annotation: ${annotation.value}") //Annotation: hello Annotation
        }
    }
}

@HelloAnnotation("hello Annotation")
fun hello(){

}
Kotlin 复制代码
//hello.kt
@file:JvmName("Hello")
package learnAnnotation

fun hello(string: String):String {
    return "Hello, $string"
}
java 复制代码
//Hi.java
package learnAnnotation;

public class Hi {
    public static void main(String[] args){
        System.out.println(Hello.hello("Annotation"));
    }
}
相关推荐
喵手1 小时前
Java 与 Oracle 数据泵实操:数据导入导出的全方位指南
java·开发语言·oracle
硬汉嵌入式2 小时前
H7-TOOL的LUA小程序教程第16期:脉冲测量,4路PWM,多路GPIO和波形打印(2024-10-25, 更新完毕)
开发语言·junit·小程序·lua
Wx120不知道取啥名2 小时前
C语言之长整型有符号数与短整型有符号数转换
c语言·开发语言·单片机·mcu·算法·1024程序员节
Python私教3 小时前
Flutter颜色和主题
开发语言·javascript·flutter
代码吐槽菌3 小时前
基于SSM的汽车客运站管理系统【附源码】
java·开发语言·数据库·spring boot·后端·汽车
Ws_3 小时前
蓝桥杯 python day01 第一题
开发语言·python·蓝桥杯
zdkdchao3 小时前
jdk,openjdk,oraclejdk
java·开发语言
神雕大侠mu4 小时前
函数式接口与回调函数实践
开发语言·python
Asin²+cos²=14 小时前
关于Android Studio Koala Feature Drop | 2024.1.2下载不了插件的解决办法
android·ide·android studio
Y.O.U..4 小时前
STL学习-容器适配器
开发语言·c++·学习·stl·1024程序员节