Kotlin 的 Equals OPERATOR 重载根本不起作用(运算符 '!=' 不能应用于 'SettingString' 和 'String'):
class SettingString(var selected) {
override infix fun equals(other: Any?) = other is String && selected == other
}
fun arbitraryFunction() {
val mode = SettingString("Boost")
mode != "Boost" // error
}
这是设计的:
Kotlin 在编译时检查值相等运算符的适用性,并可能拒绝
和A
的某些类型组合。具体来说,它使用了以下基本原理。B
如果
的类型和A
的类型绝对不同且与子类型无关,则B
是无效表达式,应导致编译时错误。A == B
通俗地说:这个原则的意思是“任何两个与子类型无关的对象都不能被
认为是相等的”。==
因为
SettingString
和String
是完全独立的、不相关的类型,编译器甚至不会尝试比较它们。这意味着如果你试图像这样隐式地比较两个完全不同的对象,这是一个错误。
你总是可以
equals()
显式,或者使用不同的关键字编写你自己的中缀运算符。如果为了可读性,也可以使用类型别名。一个值/内联类可能会遇到同样的问题,因为它编译成一个新类型(虽然将来可能会改变?)
与不是 SettingString 的对象进行比较也需要使用“as Any”进行转换:
class SettingString(private var selected: String) {
override infix fun equals(other: Any?): Boolean {
if (other is SettingString) {
return other == selected
}
return other is String && selected == other
}
override fun hashCode(): Int {
return selected.hashCode()
}
}
val mode = SettingString("Boost")
val other = SettingString("Boost")
mode != other // This obviously works
val other2 = "Boost"
mode != other2 // Doesn't work
mode != other2 as Any // This does work
!(mode equals "Boost") // This does work also
在这里查看讨论:https://discuss.kotlinlang.org/t/overloading-with-different-types-of-operands/4059/17
围绕相等运算符有一些编译器魔法——只要
equals()
的实现表现得像他们应该的那样,这就很有意义。
首先,请注意,在这种情况下,您可以按名称调用
equals()
,它将按预期使用您的覆盖方法。
然而,虽然它编译了,但它的行为不正确:你的
equals()
方法没有履行它的合同.
一方面,它不是 自反:
a.equals(a)
应该总是返回 true,但是你的方法总是返回 false。
对于另一个,它不是对称:
a.equals(b)
应该总是给出与b.equals(a)
相同的结果,但在你的例子中,mode.equals("Boost")
返回true
,而"Boost".equals(mode)
返回false
。 (毕竟,系统 String 类对您的代码一无所知。 怎么可能呢?)
不遵守
equals()
合同会导致各种奇怪的问题和意想不到的行为。 (例如,您可能会在集合或映射中获得重复值,或者它们的元素似乎随机消失并重新出现,或者迭代器可能永远不会完成。)这样的错误可能很难追踪。 一般来说,没有安全的方法允许不同类的对象进行相等比较。(如果您控制两个类及其所有公共超类,有时可以做到这一点,但很难做到正确;参见
this excellent article所有血腥细节。)
所以当你的equals()
方法编译时,恐怕它有致命的缺陷。
因为如果行为良好,不相关的类将永远不会比较相等,Kotlin 编译器使相等运算符==
和 !=
比 equals()
方法本身更具限制性:如果编译器可以告诉这两个对象不能相关,它甚至阻止你尝试比较它们。它是使语言更安全并防止某些类型的错误的众多 Kotlin 功能之一。
顺便说一句,编译器特殊对待这些运算符应该不足为奇,因为它必须这样做才能允许空参数; null == something
是有效的,即使
null.equals(something)
不是。