空安全和平台类型表示法-kotlin调用Java代码时的大坑

195 阅读2分钟

kotlin与Java代码之间是可以相互调用的,而且这种调用是无感的,殊不知这丝滑的体验中埋着一些坑。 官方链接

空安全

null空类型是kotlin中的特色,而Java是不具备空安全的。在kotlin与Java代码的相互调用时,kotlin中的null可以被映射为Java中的任意类。而且这种映射在编译阶段是被认可的。 例如Java代码:

public class MyJavaClass {
    public List<String> myFunction(String str) {
        return new ArrayList();
    }
}

Kotlin代码:

class MyKotlinClass {
    fun test() {
        val str: String? = null
        MyJavaClass().myFunction(str) // 运行时,会发出崩溃
    }
}

上面的代码可以看到,kotlin在调用Java代码时候,可以使用null代替任何一种Java类,而且在编辑阶段也不会报出来。 使用注解来避免空类型转换错误:

public class MyJavaClass {
    public List<String> myFunction(@NotNull String str) {
        return new ArrayList();
    }
}

@NotNull注解可以检查出来这种空类型转换错误。

平台类型表示法

Java中的数据结构类与Kotlin中的数据结构类之间是什么关系呢?继承关系 Kotlin中的数据结构就是继承自Java中的数据结构,只是Kotlin使用了大量的语法糖对其进行了更加精细的封装,让其更加符合Kotlin的语法风格。

@SinceKotlin("1.1") public actual typealias ArrayList<E> = java.util.ArrayList<E>
@SinceKotlin("1.1") public actual typealias LinkedHashMap<K, V> = java.util.LinkedHashMap<K, V>
@SinceKotlin("1.1") public actual typealias HashMap<K, V> = java.util.HashMap<K, V>
@SinceKotlin("1.1") public actual typealias LinkedHashSet<E> = java.util.LinkedHashSet<E>
@SinceKotlin("1.1") public actual typealias HashSet<E> = java.util.HashSet<E>

平台类型表示法:当Kotlin调用Java代码时,如果返回是Java中的数据结构类,IDE就将Java类映射为一个Kotlin类。可以如果返回类型是一个父类接口的话,这时候映射关系就不明确了。(Java和Kotlin中的数据结构接口是不互通的,比如:List<>)IDE会通过「平台类型」这种助记符来,来表示这种模糊的映射关系。

  • T! 表示“T 或者 T?”,
  • (Mutable)Collection! 表示“可以可变或不可变、可空或不可空的 T 的 Java 集合”,
  • Array<(out) T>! 表示“可空或者不可空的 T(或 T 的子类型)的 Java 数组”

空或者非空

public class MyJavaClass {
    public String myFunction() {
        return "test";
    }
}

image.png 可以看到这里IDE推测出的类型是String!, 表示这里的类型既可以是String也可以是String?, 如果直接使用this,会出现空指针异常,而IDE并没有为此发出警告。 避免出现空指针异常的情况当然也很简单: image.png

可变或者不可变(mutable or not mutable)

public class MyJavaClass {
    public List<String> myFunction() {
        return new ArrayList<String>();
    }
}

image.png 这里的(Mutable)List是指,即有可能是可变List(比如:ArrayList),也有可能是不可变List(比如:UnmodifiableLazyStringList�)。如果是UnmodifiableLazyStringList的话,add元素时,就会抛出异常。 解决的方法就是显示的变为MutableList image.png

常见的平台类型

image.png