pol*_*nts 26 java overriding overloading equals
请考虑以下代码段:
import java.util.*;
public class EqualsOverload {
public static void main(String[] args) {
class Thing {
final int x;
Thing(int x) { this.x = x; }
public int hashCode() { return x; }
public boolean equals(Thing other) { return this.x == other.x; }
}
List<Thing> myThings = Arrays.asList(new Thing(42));
System.out.println(myThings.contains(new Thing(42))); // prints "false"
}
}
Run Code Online (Sandbox Code Playgroud)
注意contains
返回false
!!! 我们似乎失去了我们的东西!
这个bug,当然是事实,我们不小心过载,而不是,重写,Object.equals(Object)
.如果我们class Thing
改为编写如下,contains
则按true
预期返回.
class Thing {
final int x;
Thing(int x) { this.x = x; }
public int hashCode() { return x; }
@Override public boolean equals(Object o) {
return (o instanceof Thing) && (this.x == ((Thing) o).x);
}
}
Run Code Online (Sandbox Code Playgroud)
有效的Java第2版,第36项:@Override
始终使用覆盖注释,使用基本相同的参数来建议应该一致地使用.当然,这个建议是好的,因为如果我们试图@Override equals(Thing other)
在第一个片段中声明,我们友好的小编译器会立即指出我们愚蠢的小错误,因为它是一个重载,而不是覆盖.
然而,这本书没有具体涉及的是重载是否equals
是一个好主意.基本上,有3种情况:
下面的代码片段说明了第三种情况:
class Thing {
final int x;
Thing(int x) { this.x = x; }
public int hashCode() { return x; }
public boolean equals(Thing other) { return this.x == other.x; }
@Override public boolean equals(Object o) {
return (o instanceof Thing) && (this.equals((Thing) o));
}
}
Run Code Online (Sandbox Code Playgroud)
在这里,即使我们现在有2个equals
方法,仍然有一个相等逻辑,它位于重载中.在@Override
简单地委托给过载.
所以问题是:
equals
,或者这几乎肯定是一种不好的做法?b_e*_*erb 17
我没有看到重载equals的情况,除了更容易出错并且更难维护,尤其是在使用继承时.
在这里,保持反身性,对称性和传递性或检测它们的不一致性是极其困难的,因为你总是必须知道被调用的实际equals方法.想想一个大的继承层次结构,只有一些类型实现自己的重载方法.
所以我会说不要这样做.
如果您的示例中有一个单独的字段,我想
@Override public boolean equals(Object o) {
return (o instanceof Thing) && (this.x == ((Thing) o).x);
}
Run Code Online (Sandbox Code Playgroud)
是要走的路.任何其他东西都会过于复杂.但是如果你添加一个字段(并且不想通过sun传递80列建议),它看起来就像
@Override public boolean equals(Object o) {
if (!(o instanceof Thing))
return false;
Thing t = (Thing) o;
return this.x == t.x && this.y == t.y;
}
Run Code Online (Sandbox Code Playgroud)
我认为这比稍微有些丑陋
public boolean equals(Thing o) {
return this.x == o.x && this.y == o.y;
}
@Override public boolean equals(Object o) {
// note that you don't need this.equals().
return (o instanceof Thing) && equals((Thing) o);
}
Run Code Online (Sandbox Code Playgroud)
所以我的经验法则基本上是,如果需要在覆盖中多次投射它,请执行override-/overload-combo.
甲次要方面是运行时开销.作为Java性能编程,第2部分:构建成本解释:
向下转换操作(在Java语言规范中也称为缩小转换)将祖先类引用转换为子类引用.此转换操作会产生执行开销,因为Java要求在运行时检查转换以确保它是有效的.
通过使用overload-/override-combo,编译器在某些情况下(不是全部!)可以在没有downcast的情况下进行管理.
要评论@Snehal点,暴露两种方法可能会混淆客户端开发人员:另一种选择是让重载的equals成为私有.保留了优雅,方法可以在内部使用,而客户端的接口看起来像预期的那样.
归档时间: |
|
查看次数: |
13574 次 |
最近记录: |