在Kotlin中有两个比较运算符:
== — 结构比较(等同于 .equals())。它检查内容:a == b 调用 a?.equals(b) ?: (b == null)。=== — 引用比较。检查两个变量是否指向同一个对象:a === b 等同于Java中的 a == b 针对对象。对于基本类型(例如,Int):== 和 === 由于自动打包可能表现相同,但一般情况下应该使用 ==。
val a = "Kotlin" val b = "Kotlin" val c = a println(a == b) // true(内容比较) println(a === b) // false(不同引用 - 字符串的内部化取决于编译器) println(a === c) // true(同一个对象)
在Kotlin中 a.equals(b) 和 a == b 有何区别?
一些人认为没有区别,然而如果 a 是可空的,则调用 a.equals(b) 会引发NullPointerException,而 a == b 是安全的,如果两者都是null则返回true,如果只有一个是null则返回false。
示例:
val a: String? = null val b: String? = null println(a == b) // true println(a?.equals(b)) // null(而不是true,但不是崩溃) println(a.equals(b)) // NullPointerException
故事
在一个大型项目中,开发人员通过 a.equals(b) 积极比较可空字符串,未意识到当 a == null 时应用程序会崩溃。这个bug虽然很少复现,但在生产环境中导致了严重的崩溃——通过改为 a == b 修复了这个问题。
故事
在通过 === 比较对象时,期望比较内容,但 === 检查的是对象的身份——结果发现两个内容相同的不同字符串在 === 下不相等,打破了数据缓存的逻辑。
故事
在处理盒装Int值(例如,来自集合)时,开发人员通过 === 进行比较,并由于不同数字的对象实例不一定像基本类型那样被内部化而得到意想不到的结果。这导致在处理对象集合时出现不正确的行为。