重载是否值得 [英] Is overloading equals worthwhile
问题描述
考虑以下片段:
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"
}
}
注意contains
返回false
!!!我们好像丢了东西!!
Note that contains
returns false
!!! We seems to have lost our things!!
当然,错误在于我们不小心重载,而不是覆盖,Object.equals(Object)
.如果我们将 class Thing
写成如下,那么 contains
会按预期返回 true
.
The bug, of course, is the fact that we've accidentally overloaded, instead of overridden, Object.equals(Object)
. If we had written class Thing
as follows instead, then contains
returns true
as expected.
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);
}
}
Effective Java 2nd Edition,Item 36:Consistently use the Override annotation,使用本质上相同的论点来建议应该一致地使用 @Override
.这个建议当然很好,因为如果我们试图在第一个片段中声明 @Override equals(Thing other)
,我们友好的小编译器会立即指出我们的愚蠢的小错误,因为它是一个重载,而不是覆盖.
Effective Java 2nd Edition, Item 36: Consistently use the Override annotation, uses essentially the same argument to recommend that @Override
should be used consistently. This advice is good, of course, for if we had tried to declare @Override equals(Thing other)
in the first snippet, our friendly little compiler would immediately point out our silly little mistake, since it's an overload, not an override.
然而,本书没有具体介绍的是重载 equals
是否是一个好主意.基本上,有 3 种情况:
What the book doesn't specifically cover, however, is whether overloading equals
is a good idea to begin with. Essentially, there are 3 situations:
- 仅过载,无覆盖 -- 几乎肯定是错误的!
- 这基本上是上面的第一个片段
- 这基本上是上面的第二个片段
下面的代码片段说明了第三种情况:
The 3rd situation is illustrated by the following snippet:
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)); } }
这里,即使我们现在有 2 个
equals
方法,仍然有一个相等逻辑,它位于重载中.@Override
只是委托给重载.Here, even though we now have 2
equals
method, there is still one equality logic, and it's located in the overload. The@Override
simply delegates to the overload.所以问题是:
- 仅覆盖"与过载和覆盖组合"的优缺点是什么?
- 重载
equals
是否有理由,或者这几乎肯定是一种不好的做法?
- What are the pros and cons of "override only" vs "overload & override combo"?
- Is there a justification for overloading
equals
, or is this almost certainly a bad practice?
推荐答案
我不认为重载 equals 的情况,除了它更容易出错且更难维护,尤其是在使用继承时.
I'dont see the case for overloading equals, except that is more error-prone and harder to maintain, especially when using inheritance.
在这里,保持自反性、对称性和传递性或检测它们的不一致可能非常困难,因为您必须始终了解被调用的实际 equals 方法.想想一个大的继承层次结构,只有一些类型实现了自己的重载方法.
Here, it can be extremly hard to maintain reflexivity, symmetry and transitivity or to detect their inconsistencies, because you always must be aware of the actual equals method that gets invoked. Just think of a large inheritance hierarchie and only some of the types implementing their own overloading method.
所以我会说不要这样做.
So I'd say just don't do it.
这篇关于重载是否值得的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!