我的编程空间,编程开发者的网络收藏夹
学习永远不晚

【Kotlin】Kotlin 与 Java 互操作 ② ( @JvmField 注解字段给 Java | @JvmOverloads 注解修饰函数 | @JvmStatic 注解声明静态成员 )

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

【Kotlin】Kotlin 与 Java 互操作 ② ( @JvmField 注解字段给 Java | @JvmOverloads 注解修饰函数 | @JvmStatic 注解声明静态成员 )





一、使用 @JvmField 注解暴露 Kotlin 字段给 Java




1、Java 类中通过 Getter 和 Setter 方法访问 Kotlin 字段


在 Java 中是 不能直接访问 Kotlin 中的字段 的 , 必须 调用相应的 Getter 和 Setter 方法 , 才能进行访问 ;


代码示例 :


Kotlin 类 : 在 Kotlin 中声明的成员属性 , 默认就是 private 私有属性 , 默认为其生成了 Getter 和 Setter 方法 ;

class Hello {    var name = "Tom"}

Java 类直接调用 : 在 Java 类中 , 不能直接调用 Kotlin 字段 ;

public class HelloJava {    public static void main(String[] args) {        Hello hello = new Hello();        System.out.println(hello.name);    }}

在 Java 类中会报错 :

'name' has private access in 'Hello'

在这里插入图片描述


在 Java 类中 , 只能通过 Getter 和 Setter 方法 , 调用 Kotlin 字段 ;

public class HelloJava {    public static void main(String[] args) {        Hello hello = new Hello();        System.out.println(hello.getName());    }}

执行结果 :
在这里插入图片描述


2、Java 类中直接访问被 @JvmField 注解修饰的 Kotlin 字段


如果在 Kotlin 中 , 使用 @JvmField 注解 修饰 成员属性 , 其作用是将 Kotlin 字段暴露给 Java , 在 Java 中可以不使用 Getter 和 Setter 方法 而直接访问 Kotlin 字段 ;


Kotlin 代码 :

class Hello {    @JvmField    var name = "Tom"}

Java 代码 :

public class HelloJava {    public static void main(String[] args) {        Hello hello = new Hello();        System.out.println(hello.name);    }}

执行结果 :

在这里插入图片描述

@JvmField 注解 相当于 将 Kotlin 中的字段声明为 Java 字段 , 此时 Kotlin 不会为该字段自动生成 Getter 和 Setter 方法 ;





二、使用 @JvmOverloads 注解修饰 Kotlin 函数



在 Kotlin 中 , 函数参数 可以 自带默认值 , 调用时可以 直接传入 想要的参数即可 ;

但是在 Java 调用 Kotlin 函数 中 , Java 语言不支持 函数参数 自带默认值的 语法 , 如果传入指定的参数 , 就需要对函数进行重载 ;

在 Kotlin 中 使用 @JvmOverloads 注解修饰 Kotlin 函数 , 会自动 为 Java 用户实现 一系列的 重载函数 ;
如 : 参数列表是 ( String , age ) , 使用 @JvmOverloads 注解修饰该函数 , 会自动生成

  • 0 个参数 ,
  • 1 个参数 ,
  • 2 个参数

的函数 ;


1、Kotlin 默认参数函数调用示例


Kotlin 代码示例 : 在下面的 helloStudent 函数中 , 两个参数都设置了默认参数值 , Kotlin 中调用该函数 , 可以传入 0 , 1 , 2 个参数 , 其中传入 1 个参数还可以选择传入哪个参数 ;

class Hello {    fun helloStudent(name: String = "Tom", age: Int = 18) {        println("Student $name is $age years old , say hello !")    }}fun main() {    var hello = Hello();    hello.helloStudent()    hello.helloStudent("Jerry")    hello.helloStudent(age = 22)    hello.helloStudent("Bill", 12)}

执行结果 :

Student Tom is 18 years old , say hello !Student Jerry is 18 years old , say hello !Student Tom is 22 years old , say hello !Student Bill is 12 years old , say hello !

在这里插入图片描述

分析上述 Kotlin 代码的字节码数据 , 在 Kotlin Bytecode 中查看字节码数据 , 反编译成 Java 代码内容如下 :

// Hello.javaimport kotlin.Metadata;import kotlin.jvm.internal.Intrinsics;import org.jetbrains.annotations.NotNull;@Metadata(   mv = {1, 1, 16},   bv = {1, 0, 3},   k = 1,   d1 = {"\u0000\u001e\n\u0002\u0018\u0002\n\u0002\u0010\u0000\n\u0002\b\u0002\n\u0002\u0010\u0002\n\u0000\n\u0002\u0010\u000e\n\u0000\n\u0002\u0010\b\n\u0000\u0018\u00002\u00020\u0001B\u0005¢\u0006\u0002\u0010\u0002J\u001a\u0010\u0003\u001a\u00020\u00042\b\b\u0002\u0010\u0005\u001a\u00020\u00062\b\b\u0002\u0010\u0007\u001a\u00020\b¨\u0006\t"},   d2 = {"LHello;", "", "()V", "helloStudent", "", "name", "", "age", "", "KotlinDemo"})public final class Hello {   public final void helloStudent(@NotNull String name, int age) {      Intrinsics.checkParameterIsNotNull(name, "name");      String var3 = "Student " + name + " is " + age + " years old , say hello !";      boolean var4 = false;      System.out.println(var3);   }   // $FF: synthetic method   public static void helloStudent$default(Hello var0, String var1, int var2, int var3, Object var4) {      if ((var3 & 1) != 0) {         var1 = "Tom";      }      if ((var3 & 2) != 0) {         var2 = 18;      }      var0.helloStudent(var1, var2);   }}// HelloKt.javaimport kotlin.Metadata;@Metadata(   mv = {1, 1, 16},   bv = {1, 0, 3},   k = 2,   d1 = {"\u0000\b\n\u0000\n\u0002\u0010\u0002\n\u0000\u001a\u0006\u0010\u0000\u001a\u00020\u0001¨\u0006\u0002"},   d2 = {"main", "", "KotlinDemo"})public final class HelloKt {   public static final void main() {      Hello hello = new Hello();      Hello.helloStudent$default(hello, (String)null, 0, 3, (Object)null);      Hello.helloStudent$default(hello, "Jerry", 0, 2, (Object)null);      Hello.helloStudent$default(hello, (String)null, 22, 1, (Object)null);      hello.helloStudent("Bill", 12);   }   // $FF: synthetic method   public static void main(String[] var0) {      main();   }}

2、Java 中调用 Kotlin 默认参数函数


如果 在 Java 代码中 , 想要 像 Kotlin 那样传入任意个数和类型的参数 , 就需要使用 函数重载实现 ;

如果 直接像 Kotlin 中那样调用 , 肯定会报错 :
在这里插入图片描述

使用 @JvmOverloads 注解修饰 Kotlin 函数 , 会自动为 Java 用户实现 一系列的 重载函数 ;


Kotlin 代码示例 :

class Hello {    @JvmOverloads    fun helloStudent(name: String = "Tom", age: Int = 18) {        println("Student $name is $age years old , say hello !")    }}fun main() {    var hello = Hello();    hello.helloStudent()    hello.helloStudent("Jerry")    hello.helloStudent(age = 22)    hello.helloStudent("Bill", 12)}

Java 代码示例 :

public class HelloJava {    public static void main(String[] args) {        Hello hello = new Hello();        hello.helloStudent();        hello.helloStudent("Jerry");        hello.helloStudent("Bill", 12);    }}

执行结果 :

Student Tom is 18 years old , say hello !Student Jerry is 18 years old , say hello !Student Bill is 12 years old , say hello !

在这里插入图片描述

分析上述 使用了 @JvmOverloads 注解 的 Kotlin 类对应的字节码数据 , 将字节码反编译回 Java 代码 , 内容如下 :

// Hello.javaimport kotlin.Metadata;import kotlin.jvm.JvmOverloads;import kotlin.jvm.internal.Intrinsics;import org.jetbrains.annotations.NotNull;@Metadata(   mv = {1, 1, 16},   bv = {1, 0, 3},   k = 1,   d1 = {"\u0000\u001e\n\u0002\u0018\u0002\n\u0002\u0010\u0000\n\u0002\b\u0002\n\u0002\u0010\u0002\n\u0000\n\u0002\u0010\u000e\n\u0000\n\u0002\u0010\b\n\u0000\u0018\u00002\u00020\u0001B\u0005¢\u0006\u0002\u0010\u0002J\u001c\u0010\u0003\u001a\u00020\u00042\b\b\u0002\u0010\u0005\u001a\u00020\u00062\b\b\u0002\u0010\u0007\u001a\u00020\bH\u0007¨\u0006\t"},   d2 = {"LHello;", "", "()V", "helloStudent", "", "name", "", "age", "", "KotlinDemo"})public final class Hello {   @JvmOverloads   public final void helloStudent(@NotNull String name, int age) {      Intrinsics.checkParameterIsNotNull(name, "name");      String var3 = "Student " + name + " is " + age + " years old , say hello !";      boolean var4 = false;      System.out.println(var3);   }   // $FF: synthetic method   public static void helloStudent$default(Hello var0, String var1, int var2, int var3, Object var4) {      if ((var3 & 1) != 0) {         var1 = "Tom";      }      if ((var3 & 2) != 0) {         var2 = 18;      }      var0.helloStudent(var1, var2);   }   @JvmOverloads   public final void helloStudent(@NotNull String name) {      helloStudent$default(this, name, 0, 2, (Object)null);   }   @JvmOverloads   public final void helloStudent() {      helloStudent$default(this, (String)null, 0, 3, (Object)null);   }}// HelloKt.javaimport kotlin.Metadata;@Metadata(   mv = {1, 1, 16},   bv = {1, 0, 3},   k = 2,   d1 = {"\u0000\b\n\u0000\n\u0002\u0010\u0002\n\u0000\u001a\u0006\u0010\u0000\u001a\u00020\u0001¨\u0006\u0002"},   d2 = {"main", "", "KotlinDemo"})public final class HelloKt {   public static final void main() {      Hello hello = new Hello();      Hello.helloStudent$default(hello, (String)null, 0, 3, (Object)null);      Hello.helloStudent$default(hello, "Jerry", 0, 2, (Object)null);      Hello.helloStudent$default(hello, (String)null, 22, 1, (Object)null);      hello.helloStudent("Bill", 12);   }   // $FF: synthetic method   public static void main(String[] var0) {      main();   }}

使用了 @JvmOverloads 注解后 ,
在编译时 , 自动为 helloStudent 函数 , 生成了 0 , 1, 2 个参数的重载函数 ,
这样在 Java 中调用时 , 可以直接调用这些方法 ;

   @JvmOverloads   public final void helloStudent(@NotNull String name, int age) {      Intrinsics.checkParameterIsNotNull(name, "name");      String var3 = "Student " + name + " is " + age + " years old , say hello !";      boolean var4 = false;      System.out.println(var3);   }   @JvmOverloads   public final void helloStudent(@NotNull String name) {      helloStudent$default(this, name, 0, 2, (Object)null);   }   @JvmOverloads   public final void helloStudent() {      helloStudent$default(this, (String)null, 0, 3, (Object)null);   }




三、使用 @JvmStatic 注解声明静态成员



在 Kotlin 中 , 没有静态成员概念 , 需要声明静态成员时 , 一般都在其 Companion 伴生对象中声明 ;

在 Java 中 调用 Kotlin 的 Companion 伴生对象 中的成员时 , 需要通过如下形式进行调用 :

Kotlin.Companion.成员属性Kotlin.Companion.成员函数

如果想要 在不使用 Companion 的前提下 直接调用 Kotlin 中的 Companion 伴生对象 成员 ,

可以 在 companion object 中 ,

使用 @JvmStatic 注解 将伴生对象中的成员 声明 为 Java 静态成员 ,

Java 中可以按照静态成员的方式进行访问 ;


1、Java 正常访问 Kotlin 伴生对象成员


在下面的代码中 , 在 Java 语言中访问 Kotlin 伴生对象成员 , 需要先获取 Hello.Companion 类的伴生对象 , 然后再访问 伴生对象 中的成员 ;


Kotlin 代码 :

class Hello {    companion object {        var name = "Tom"        fun say() {            println("Hello World")        }    }}

Java 代码 :

public class HelloJava {    public static void main(String[] args) {        System.out.println(Hello.Companion.getName());        Hello.Companion.say();    }}

执行结果 :

TomHello World

在这里插入图片描述


查看该 Kotlin 类生成的字节码 反编译 的 Java 代码 :

import kotlin.Metadata;import kotlin.jvm.internal.DefaultConstructorMarker;import kotlin.jvm.internal.Intrinsics;import org.jetbrains.annotations.NotNull;@Metadata(   mv = {1, 1, 16},   bv = {1, 0, 3},   k = 1,   d1 = {"\u0000\f\n\u0002\u0018\u0002\n\u0002\u0010\u0000\n\u0002\b\u0003\u0018\u0000 \u00032\u00020\u0001:\u0001\u0003B\u0005¢\u0006\u0002\u0010\u0002¨\u0006\u0004"},   d2 = {"LHello;", "", "()V", "Companion", "KotlinDemo"})public final class Hello {   @NotNull   private static String name = "Tom";   public static final Hello.Companion Companion = new Hello.Companion((DefaultConstructorMarker)null);   @Metadata(      mv = {1, 1, 16},      bv = {1, 0, 3},      k = 1,      d1 = {"\u0000\u001a\n\u0002\u0018\u0002\n\u0002\u0010\u0000\n\u0002\b\u0002\n\u0002\u0010\u000e\n\u0002\b\u0005\n\u0002\u0010\u0002\n\u0000\b\u0086\u0003\u0018\u00002\u00020\u0001B\u0007\b\u0002¢\u0006\u0002\u0010\u0002J\u0006\u0010\t\u001a\u00020\nR\u001a\u0010\u0003\u001a\u00020\u0004X\u0086\u000e¢\u0006\u000e\n\u0000\u001a\u0004\b\u0005\u0010\u0006\"\u0004\b\u0007\u0010\b¨\u0006\u000b"},      d2 = {"LHello$Companion;", "", "()V", "name", "", "getName", "()Ljava/lang/String;", "setName", "(Ljava/lang/String;)V", "say", "", "KotlinDemo"}   )   public static final class Companion {      @NotNull      public final String getName() {         return Hello.name;      }      public final void setName(@NotNull String var1) {         Intrinsics.checkParameterIsNotNull(var1, "");         Hello.name = var1;      }      public final void say() {         String var1 = "Hello World";         boolean var2 = false;         System.out.println(var1);      }      private Companion() {      }      // $FF: synthetic method      public Companion(DefaultConstructorMarker $constructor_marker) {         this();      }   }}

在 Kotlin 编译成的字节码数据中 , name 成员属性 和 say 成员函数 , 都定义在了 Hello.Companion 伴生对象中 , 如果要访问 这两个成员 , 必须通过 Hello.Companion 进行访问 ;


2、Java 以静态方式访问 Kotlin 伴生对象成员


在下面的代码中 , 使用 @JvmStatic 注解修饰 Kotlin 中伴生对象中的成员 , 则可以在 Java 中 以静态方式访问这些成员 ;


Kotlin 代码 :

class Hello {    companion object {        @JvmStatic        var name = "Tom"        @JvmStatic        fun say() {            println("Hello World")        }    }}

Java 代码 :

public class HelloJava {    public static void main(String[] args) {        System.out.println(Hello.getName());        Hello.say();    }}

执行结果 :
在这里插入图片描述


查看该 Kotlin 类生成的字节码 反编译 的 Java 代码 :

import kotlin.Metadata;import kotlin.jvm.JvmStatic;import kotlin.jvm.internal.DefaultConstructorMarker;import kotlin.jvm.internal.Intrinsics;import org.jetbrains.annotations.NotNull;@Metadata(   mv = {1, 1, 16},   bv = {1, 0, 3},   k = 1,   d1 = {"\u0000\f\n\u0002\u0018\u0002\n\u0002\u0010\u0000\n\u0002\b\u0003\u0018\u0000 \u00032\u00020\u0001:\u0001\u0003B\u0005¢\u0006\u0002\u0010\u0002¨\u0006\u0004"},   d2 = {"LHello;", "", "()V", "Companion", "KotlinDemo"})public final class Hello {   @NotNull   private static String name = "Tom";   public static final Hello.Companion Companion = new Hello.Companion((DefaultConstructorMarker)null);   @NotNull   public static final String getName() {      Hello.Companion var10000 = Companion;      return name;   }   public static final void setName(@NotNull String var0) {      Hello.Companion var10000 = Companion;      name = var0;   }   @JvmStatic   public static final void say() {      Companion.say();   }   @Metadata(      mv = {1, 1, 16},      bv = {1, 0, 3},      k = 1,      d1 = {"\u0000\u001a\n\u0002\u0018\u0002\n\u0002\u0010\u0000\n\u0002\b\u0002\n\u0002\u0010\u000e\n\u0002\b\u0006\n\u0002\u0010\u0002\n\u0000\b\u0086\u0003\u0018\u00002\u00020\u0001B\u0007\b\u0002¢\u0006\u0002\u0010\u0002J\b\u0010\n\u001a\u00020\u000bH\u0007R$\u0010\u0003\u001a\u00020\u00048\u0006@\u0006X\u0087\u000e¢\u0006\u0014\n\u0000\u0012\u0004\b\u0005\u0010\u0002\u001a\u0004\b\u0006\u0010\u0007\"\u0004\b\b\u0010\t¨\u0006\f"},      d2 = {"LHello$Companion;", "", "()V", "name", "", "name$annotations", "getName", "()Ljava/lang/String;", "setName", "(Ljava/lang/String;)V", "say", "", "KotlinDemo"}   )   public static final class Companion {            // $FF: synthetic method      @JvmStatic      public static void name$annotations() {      }      @NotNull      public final String getName() {         return Hello.name;      }      public final void setName(@NotNull String var1) {         Intrinsics.checkParameterIsNotNull(var1, "");         Hello.name = var1;      }      @JvmStatic      public final void say() {         String var1 = "Hello World";         boolean var2 = false;         System.out.println(var1);      }      private Companion() {      }      // $FF: synthetic method      public Companion(DefaultConstructorMarker $constructor_marker) {         this();      }   }}

Kotlin 类编译 时 , 自动生成了

  • Hello.name 静态成员 以及 其 静态的 Getter 和 Setter 方法 ,
  • Hello.say 静态方法 ;

这 两个静态 成员都是 Kotlin 类中的 Hello.Companion 伴生对象 中的成员 , 但是编译时生成在了 Hello 类中 , 称为了 Hello 类的成员 ;

public final class Hello {   @NotNull   private static String name = "Tom";   @NotNull   public static final String getName() {      Hello.Companion var10000 = Companion;      return name;   }   public static final void setName(@NotNull String var0) {      Hello.Companion var10000 = Companion;      name = var0;   }   @JvmStatic   public static final void say() {      Companion.say();   }}

来源地址:https://blog.csdn.net/shulianghan/article/details/129109314

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

【Kotlin】Kotlin 与 Java 互操作 ② ( @JvmField 注解字段给 Java | @JvmOverloads 注解修饰函数 | @JvmStatic 注解声明静态成员 )

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

【Kotlin】Kotlin 与 Java 互操作 ② ( @JvmField 注解字段给 Java | @JvmOverloads 注解修饰函数 | @JvmStatic 注解声明静态成员 )

文章目录 一、使用 @JvmField 注解暴露 Kotlin 字段给 Java1、Java 类中通过 Getter 和 Setter 方法访问 Kotlin 字段2、Java 类中直接访问被 @JvmField 注解修饰的 Kot
2023-08-19

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录