5.10 相等性
3 分钟阅读
5.10 相等性
在 Kotlin 中,有两种相等性:
- 结构相等性(
==)—— 对equals()函数的检查 - 引用相等性(
===)—— 检查两个引用是否指向同一个对象
结构相等性
结构相等性用于验证两个对象是否具有相同的内容或结构。结构相等性由 == 运算及其取反形式 != 检查。按照约定,像 a == b 这样的表达式会被转换为:
| |
如果 a 不为 null,就调用 equals(Any?) 函数。否则(a 为 null),则检查 b 是否在引用上等于 null:
| |
注意,与 null 显式比较时没有必要优化代码:a == null 会被自动转换为 a === null。
在 Kotlin 中,所有类都从 Any 类继承 equals() 函数。默认情况下,equals() 函数实现的是引用相等性。不过,Kotlin 中的类可以重写 equals() 函数来提供自定义的相等性逻辑,从而实现结构相等性。
值类和数据类是两种会自动重写 equals() 函数的特殊 Kotlin 类型,因此它们默认实现结构相等性。
不过,对于数据类,如果 equals() 函数在父类中被标记为 final,它的行为就保持不变。
不同的是,非数据类(未用 data 修饰符声明的类)默认不会重写 equals() 函数。非数据类实现的是从 Any 类继承的引用相等性行为。要实现结构相等性,非数据类需要自定义相等性逻辑来重写 equals() 函数。
要提供自定义的相等性检查实现,请重写 equals(other: Any?): Boolean 函数:
| |
注意: 重写 equals() 函数时,你也应当重写 hashCode() 函数,以保持相等性与哈希的一致性,并确保这些函数行为正确。
同名但签名不同的函数(例如 equals(other: Foo))不会影响 == 和 != 运算符的相等性检查。
结构相等性与 Comparable<...> 接口定义的比较无关,因此只有自定义的 equals(Any?) 实现才会影响该运算符的行为。
引用相等性
引用相等性检查两个对象的内存地址,以判断它们是否是同一个实例。
引用相等性由 === 运算及其取反形式 !== 检查。当且仅当 a 和 b 指向同一个对象时,a === b 的结果为 true:
| |
对于运行时由基本类型表示的值(例如 Int),=== 相等性检查等价于 == 检查。
提示: 引用相等性在 Kotlin/JS 中的实现方式不同。关于相等性的更多信息,请参阅 Kotlin/JS 文档。
浮点数相等性
当相等性检查的操作数在静态类型上已知为 Float 或 Double(无论是否可空)时,该检查遵循 IEEE 754 浮点运算标准。
对于静态类型不是浮点数的操作数,行为有所不同。在这些情况下,实现的是结构相等性。因此,操作数静态类型不是浮点数的检查与 IEEE 标准存在差异。在这种场景下:
NaN等于其自身NaN大于任何其他元素(包括POSITIVE_INFINITY)-0.0不等于0.0
更多信息请参阅浮点数比较。
数组相等性
要比较两个数组是否包含顺序相同的相同元素,请使用 contentEquals()。
更多信息请参阅比较数组。