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";
}
}
可以看到这里IDE推测出的类型是
String!
, 表示这里的类型既可以是String
也可以是String?
, 如果直接使用this
,会出现空指针异常,而IDE并没有为此发出警告。
避免出现空指针异常的情况当然也很简单:
可变或者不可变(mutable or not mutable)
public class MyJavaClass {
public List<String> myFunction() {
return new ArrayList<String>();
}
}
这里的
(Mutable)List
是指,即有可能是可变List
(比如:ArrayList
),也有可能是不可变List
(比如:UnmodifiableLazyStringList�
)。如果是UnmodifiableLazyStringList
的话,add元素时,就会抛出异常。
解决的方法就是显示的变为MutableList