Kotlin与Java混合开发(2)✔️Kotlin调用Java

  • 避免 kotlin 关键字
  • 平台类型与空值
  • 异常检查
  • 调用 Java 函数式接口

  混合编程包含两个方面:Kotlin 调用 JavaJava 调用 Kotlin

避免 kotlin 关键字

  因为 Kotlin 出现的比 Java 要晚许多,所以在 Java 程序员在给 Java 标识符命名时并没有考虑到哪些是 Kotlin 的关键字。但在 Kotlin 中调用这样的 Java 代码时,则需要将这些关键字用 反引号(`) 括起来。例如 Java 标准输出流 System.in,如果在 Kotlin 中调用则需要表示为 System.`in`

// JavaClass.java
public class JavaClass {
    public static JavaClass object = new JavaClass();

    @Override
    public String toString() {
        return this.getClass().getSimpleName();
    }
}
// main.kt
fun main(args: Array?) {
    val obj = JavaClass.`object`
    println(obj)
}
// 运行结果:
JavaClass
Process finished with exit code 0

平台类型与空值

  前面提到过 平台类型,这些类型在 Java 中声明了一个变量或者返回值,它的类型可能为空,也可能非空。Kotlin 在调用它们时会放弃类型检查。

// Person.java
public class Person {
    private String name = "小三";
    private int age = 20;
    private Date birthDate; // 未初始化,为空值 null

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public Date getBirthDate() {
        return birthDate;
    }

    public void setBirthDate(Date birthDate) {
        this.birthDate = birthDate;
    }
}
// mian.kt
fun main(args: Array?) {
    val person = Person()
    val date = person.birthDate // 1️⃣ 编译器自动推导,为平台类型
    println("date = $date")

    val date1: Date? = person.birthDate // 指定类型Date?,可为空类型
    println("date1 = $date1")

    val date2: Date = person.birthDate // 2️⃣指定类型Date,不能为空。
    println("date2 = $date2")
}
// 运行结果
date = null
date1 = null
Exception in thread "main" java.lang.IllegalStateException: person.birthDate must not be null
    at cn.ak.kotmodule.WwwwKt.main(wwww.kt:21)

  上面编写了一个 Java 类 Person,它的 birthDate 字段没有初始化所以为空值。在 Kotlin 中通过属性访问 Java 中的 settergetter 函数,代码第1️⃣行读取 birthDate 属性赋值给变量 date,此时 date 的类型是由编译器自动推导出来的,所以 IntelliJ IDEA IDE 表示的平台类型是 Date!,它可以接收空值。
  但是如果明确指定返回值类型,可以使用 Date?Date。由于 Date? 是可空类型,date1 可以接收空值,而 date2 是非空类型,不能接收空值,因此代码第2️⃣行会发生异常。

我们将上面 mian.kt 反编译回 Java 文件会是什么样子?

   public static final void main(@Nullable String[] args) {
      Person person = new Person();
      // 赋值,但未对date空值检查
      Date date = person.getBirthDate(); 
      String var3 = "date = " + date;
      boolean var4 = false;
      System.out.println(var3);
      // 赋值,但未对date1空值检查
      Date date1 = person.getBirthDate();  
      String var8 = "date1 = " + date1;
      boolean var5 = false;
      System.out.println(var8);
      // 临时获取birthDate值存储在临时变量var10000中
      Date var10000 = person.getBirthDate();  
      // 如果var10000这个临时变量是空值,抛出异常
      Intrinsics.checkExpressionValueIsNotNull(var10000, "person.birthDate"); 
      // 使用var10000值对 date2 初始化
      Date date2 = var10000;  
      String var10 = "date2 = " + date2;
      boolean var6 = false;
      System.out.println(var10);
   }

  从反编译后的代码可以看出,datedate1 都没有做空值的检查,只有 date2 通过代码 Intrinsics.checkExpressionValueIsNotNull(var10000, "person.birthDate"); 检查了空值,并且是空值会抛出异常。

异常检查

  Kotlin 和 Java 在异常检查上有很大的不同,Java 有受检查异常,而 Kotlin 中没有受检查异常。那么当 Kotlin 调用 Java 中的一个函数时,这个函数声明抛出异常,那么 Kotlin 会如何处理?

fun main(args: Array?) {
    try {
        InputStreamReader(System.`in`).use { isr ->  // 1️⃣
            BufferedReader(isr).use { reader ->      // 2️⃣
                val command = reader.readLine()      // 3️⃣
                println(command)
            }
        }
    } catch (e: IOException) {
        e.printStackTrace()
    }
}

  代码第1️⃣行~第3️⃣行是通过 Java 标准输入流从键盘读取字符串,相当于 Kotlin 中的 readLine() 函数。这里创建了两个输入流代码,见代码第1️⃣行和第2️⃣行。一个读取数据的函数见代码第3️⃣行,它们都会抛出 IOException 异常。IOException 在 Java 中是受检查异常,必须要进行捕获或抛出处理,而 Kotlin 中不用必须捕获。

调用 Java 函数式接口

  Java 函数式接口中 只有一个抽象函数接口,简称 SAM (Single Abstract Method),在 Kotlin 中调用 Java 函数式接口非常简单,形式是 接口名{...}

// Calculable.java
public interface Calculable {
    int calculateInt(int a, int b);
}
// main.kt
fun main(args: Array?) {
    val n1 = 10
    val n2 = 5

    // 实现加法计算的Calculable对象
    val f1 = Calculable { a, b -> a + b }
    // 实现减法计算的Calculable对象
    val f2 = Calculable { a, b -> a - b }

    // 调用calculateInt函数进行加法计算
    println("$n1 + $n2 = ${f1.calculateInt(n1, n2)}")
    // 调用calculateInt函数进行减法计算
    println("$n1 - $n2 = ${f2.calculateInt(n1, n2)}")
}
// 运行结果
10 + 5 = 15
10 - 5 = 5
Process finished with exit code 0

你可能感兴趣的:(Kotlin与Java混合开发(2)✔️Kotlin调用Java)