📜  Java互操作性——从Java调用 Kotlin

📅  最后修改于: 2022-05-13 01:55:48.709000             🧑  作者: Mango

Java互操作性——从Java调用 Kotlin

开发 Kotlin 时,它仅在JVM上运行,因此它提供了一套完整的功能,使从Java调用 Kotlin 变得非常容易。例如,可以轻松创建 Kotlin 类的对象,并且可以在Java方法中调用它们的方法。但是,有一些关于如何在Java中使用 Kotlin 代码的规则。

Kotlin 属性 –

Kotlin 中的属性在Java中定义为与属性名称相同的私有字段,以及getter 和 setter函数getset前缀为属性名称。这个私有字段存在于从 kotlin 文件生成的Java类中。
例如,属性var age: Int在Java中被编译为以下代码 -

private int age;
  
public int getAge(){
  return age;
}
public void setAge(int age){
  this.age = value;
}

这些属性可以使用类的对象来访问,就像在Java中一样。但是,如果属性名称以is开头,那么getter函数名称中的 get 关键字将被跳过。

包级功能 –

Kotlin 文件中定义的所有函数,在一个包中都被编译成Java中的静态方法,该类的类名是包名和文件名的组合

例如,如果有一个名为kotlinPrograms的包和一个名为firstProgram.kt的 Kotlin 文件,其内容如下。

// Kotlin file
  
package kotlinPrograms
  
class myClass {
  
  fun add(val a:Int, val b:Int): Int {
   return a+b;
 }
}

可以使用以下语法在Java中调用此函数:

// Java
new kotlinPrograms.firstProgram.myClass()
kotlinPrograms.FirstProgramkt.add(3, 5);

我们可以使用@JvmName注解更改生成的Java类的名称。

// Kotlin file
@file : Jvmname("Sample")
  
package kotlinPrograms
  
class myClass {
  
  fun add(val a:Int, val b:Int): Int {
   return a+b;
 }
}

可以使用以下语法在Java中调用此函数:

// Java
new kotlinPrograms.firstProgram.myClass()
kotlinPrograms.Sample.add(3, 5);

但是,拥有多个同名文件在逻辑上是错误的。为了克服这个问题,Kotlin 为其编译器提供了创建具有特定名称的外观类的能力,并包含来自所有同名文件的所有声明。要创建这样的外观类,请在所有文件中添加注解@JvmMultiFileClass注解。

例子

// Kotlin code
@file:JvmName("Sample")
@file:JvmMultiFileClass
  
package sample.example
  
fun print(){.......}

另一个 Kotlin 文件——

// Kotlin code
@file:JvmName("Sample")
@file:JvmMultiFileClass
  
package sample.example
  
fun printString(){.......}

这两个函数都可以使用以下语法在Java中调用:

// Java calling statements
sample.example.Sample.print()
sample.example.Sample.printString()

静态字段 –

Kotlin 中在命名对象或伴随对象中声明的属性在Java中用作静态字段。要在Java中访问这些字段,这些字段必须使用@JvmField注释、lateinit 修饰符进行注释,或者必须使用const修饰符进行声明。

示例

// filename Program.kt
  
// Property in a companion object
class abc{
 companion object{
      @JvmField
      val x = 5;
  }
}
  
// A constant property
const val y = 5;
//Java Usage
abc.x
Programkt.y

静态方法——

在包级别定义的方法总是在Java文件中生成为静态方法。如果使用@JvmStatic注释进行注释,则在命名对象伴随对象中定义的方法也会生成为静态方法。此注释将以下函数声明为类函数。

伴随对象的示例

// filename Programs.kt
class abc {
  companion object {
     @JvmStatic fun add(val a:Int, val b:Int):Int{
        return a+b;
      }
     fun sub(val a:Int, val b:Int):Int{
        return a-b;
      }
   }
}
//Java usage
abc.add(); // works fine
abc.sub(); // error: not a static method
abc.Companion.add(); // instance method remains
C.Companion.sub(); // the only way it works

同样,它适用于命名对象。

实例字段 –

Kotlin 提供了在Java中将属性用作实例字段的功能。为此,请使用@JvmField注释对属性进行注释。这些实例字段与 Kotlin 属性具有相同的可见性。但是,该属性必须有一个支持字段,并且不能使用privateopenconstoverride修饰符声明。

例子

// Kotlin code
class ABC(c: Int){
 @JvmField val id = c
}

这个属性现在可以在Java中访问为

ABC obj = new ABC(5);
System.out.println(obj.id);

检查异常

Kotlin 中的所有异常都是未经检查的。因此,Kotlin 函数的Java签名既不声明也不处理抛出的异常。为了克服这个问题,Kotlin函数必须使用@Throws注释来指定将被抛出的异常。在这种情况下, Java签名还将声明要抛出的函数。

例子

// A sample Kotlin function
  
// filename program.kt
package Sample
  
fun print(){
 throws IOException()
}
// Java code trying to call the above  function
try {
    Sample.Program.print(); 
    }
   // This statement causes error because does not declare IOexception in throws list
   catch(IOException e) { 
}

因此,为了解决错误,我们在顶部声明了 @Throws注释。

// Overcoming the problem with @Throws annotation
package Sample
  
@Throws(IOException::class)
fun print()
{
throws IOException()
}