是否可以equals在 Kotlin 接口中编写方法的默认实现?
我有这个代码:
interface User {
val id: String
}
Run Code Online (Sandbox Code Playgroud)
我希望所有实现 User 的类都使用id属性进行比较。像这样的东西:
interface User {
val id: String
fun equals(other: Any?) : Boolean {
//check type and stuff
return id == other.id
}
}
Run Code Online (Sandbox Code Playgroud)
我知道我可以(也许应该)使用抽象类,但我现在必须处理这种情况。
谢谢
不,恐怕这是不可能的。
\n\n如果您尝试您的代码,编译器会抱怨:
\n\n\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0\'equals\' hides member of supertype \'Any\' and needs \'override\' modifier
如果添加override修饰符:
\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0An interface may not implement a method of \'Any\'
原因有点晦涩,是从 Java 继承的(!)。
\n\n最初,接口只能包含抽象方法(和常量字段)。\xc2\xa0 当添加在接口中指定方法实现的功能时,这样做是为了不破坏现有代码,因此它们仅适用于类还没有实现。\xc2\xa0 (在 Java 中,它们被称为 \xe2\x80\x98default\xe2\x80\x99 方法来强化这一点。)\xc2\xa0 如果一个类有一个实现,无论是在类中还是在超类中定义,都会使用它,并且默认值将被忽略。
\n\n不过,有一些极端情况:Object中定义的方法(Java 相当于 Kotlin 的Any)。\xc2\xa0 这些方法是clone()、equals()、Finalize()、getClass()、hashCode()、notify()、notifyAll()、toString()和wait() .\xc2\xa0 (其中大多数现在很少直接使用,但当然equals()、hashCode()、 和toString()非常重要。)
因为这些方法是在 中定义的Object,所以每个类都有它们的直接实现(来自Object或某个子类)。\xc2\xa0 因此永远不能使用接口的默认实现。
事实上,这同样适用于 Kotlin/JVM 以及Any\xe2\x80\x94 中定义的相应方法,如果您尝试提供任何这些方法的默认实现,编译器会通过给出错误来明确它,如上所示。
这是一种耻辱,因为在某些情况下,默认实现equals()、hashCode()和/或toString()会非常有用!\xc2\xa0 但它会带来复杂性、脆弱性和一些令人惊讶的极端情况;看这个答案有权威的解释。