Java类中java.lang.CharSequence成员未按预期完成类型检查问题
结论
这个编译行为是Kotlin官方有意设计的,核心是Kotlin对Kotlin原生声明类型和Java互操作的平台类型采用了不同的相等性检查规则。
具体原因
首先是Kotlin原生代码的检查逻辑
Kotlin会把代码中显式声明的java.lang.CharSequence统一映射为kotlin.CharSequence接口。Kotlin官方为了避免开发者写出不符合预期的相等性判断代码,默认禁止不同CharSequence子类型(比如String、StringBuilder、CharBuffer等)之间直接使用==运算符比较:因为不同子类型的equals实现没有跨类型相等的约定,比如StringBuilder("hi") == "hi"一定会返回false,这类逻辑错误很容易被忽略,所以编译器直接做了拦截,你写的第一个Kotlin类的场景触发的就是这个检查。其次是Java互操作的特殊处理
Java类中声明的java.lang.CharSequence字段,在Kotlin侧会被识别为平台类型。Kotlin为了降低Java-Kotlin互操作的成本,专门放宽了平台类型的相等性检查规则:Java生态中大量存在CharSequence和String直接用==/equals比较的代码,如果Kotlin对这类场景也做强制拦截,会导致大量现有Java代码无法在Kotlin中正常调用,所以官方特意做了兼容,允许平台类型的CharSequence和String直接用==比较。
最佳实践建议
如果要在Kotlin代码中安全比较两个CharSequence的内容是否相等,不管是原生类型还是平台类型,都推荐使用Kotlin标准库提供的contentEquals扩展方法,写法如下:
println(foo.bar.contentEquals("hi"))
这个方法会兼容所有CharSequence子类型的内容比较,符合绝大多数场景的预期。
内容的提问来源于stack exchange,提问作者Tobias Hermann

