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"));
    }
}
相关推荐
Coding小公仔33 分钟前
C++ bitset 模板类
开发语言·c++
雨白44 分钟前
Jetpack系列(二):Lifecycle与LiveData结合,打造响应式UI
android·android jetpack
小赖同学啊1 小时前
物联网数据安全区块链服务
开发语言·python·区块链
shimly1234561 小时前
bash 脚本比较 100 个程序运行时间,精确到毫秒,脚本
开发语言·chrome·bash
IT_10241 小时前
Spring Boot项目开发实战销售管理系统——数据库设计!
java·开发语言·数据库·spring boot·后端·oracle
new_zhou2 小时前
Windows qt打包编译好的程序
开发语言·windows·qt·打包程序
ye902 小时前
银河麒麟V10服务器版 + openGuass + JDK +Tomcat
java·开发语言·tomcat
武昌库里写JAVA2 小时前
Oracle如何使用序列 Oracle序列使用教程
java·开发语言·spring boot·学习·课程设计
kk爱闹2 小时前
【挑战14天学完python和pytorch】- day01
android·pytorch·python