为什么 Java 的 Area#equals 方法不覆盖 Object#equals?

Why does Java's Area#equals method not override Object#equals?

我刚刚 运行 遇到了由 Java 的 java.awt.geom.Area#equals(Area) 方法引起的问题。问题可以简化为如下单元测试:

@org.junit.Test
public void testEquals() {
    java.awt.geom.Area a = new java.awt.geom.Area();
    java.awt.geom.Area b = new java.awt.geom.Area();
    assertTrue(a.equals(b)); // -> true

    java.lang.Object o = b;
    assertTrue(a.equals(o)); // -> false
}

经过一番摸索和调试,我终于在JDK源码中看到,Areaequals方法的签名是这样的:

public boolean equals(Area other)

请注意,它不是 @Override Object 中的普通 equals 方法,而只是用更具体的方法重载该方法类型。因此,上面示例中的两个调用最终调用了 equals.

的不同实现

由于此行为自 Java 1.2 以来一直存在,因此我认为它不被视为错误。因此,我更感兴趣的是找出 为什么 决定 而不是 正确覆盖 equals 方法,但在同时提供重载变体。 (另一个表明这是一个实际决定的暗示是没有被覆盖的 hashCode() 方法。)

我唯一的猜测是,作者担心在 SetMap 中放置 Area 时,区域的缓慢 equals 实现不适合比较相等性,ETC。数据结构。 (在上面的示例中,您可以将 a 添加到 HashSet,尽管 b 等于 a,但调用 contains(b) 将失败。) ,为什么他们不只是以不与 equals 方法这样的基本概念冲突的方式命名有问题的方法?

“为什么 Java 的 Area#equals 方法不覆盖 Object#equals?”

因为对于参数类型不同的重载方法,不需要覆盖。

An overridden method would have the exact same method name, return type, number of parameters, and types of parameters as the method in the parent class, and the only difference would be the definition of the method.

这种情况不会迫使我们覆盖,但它会超载,因为它遵循以下规则:

1.) The number of parameters is different for the methods.

2.) The parameter types are different (like changing a parameter that was a float to an int).

“为什么他们不以不与 equals 方法这样的基本概念冲突的方式命名有问题的方法?”

因为这可能会绊倒人们走向未来。如果我们有一台到 90 年代的时光机,我们就可以不用担心。

RealSkeptic 链接到 JDK-4391558 in a comment above. The comment 在该错误中解释了原因:

The problem with overriding equals(Object) is that you must also override hashCode() to return a value which guarantees that equals() is true only if the hashcodes of the two objects are also equal.

但是:

The problem here is that Area.equals(Area) does not perform a very straight-forward comparison. It painstakingly examines each and every piece of geometry in the two Areas and tests to see if they cover the same enclosed spaces. Two Area objects could have a completely different description of the same enclosed space and equals(Area) would detect that they were the same.

所以基本上我们留下了一系列不太令人愉快的选项,例如:

deprecate equals(Area) and create an alternate name for that operation, such as "areasEqual" so as to avoid the confusion. Unfortunately, the old method would remain and would be linkable and would trap many people who were intending to invoke the equals(Object) version.

或:

deprecate equals(Area) and change its implementation to be exactly that of equals(Object) so as to avoid semantic problems if the wrong method is called. Create a new method with a different name to avoid confusion to implement the old functionality provided by equals(Area).

或:

implement equals(Object) to call equals(Area) and implement a dummy hashCode() which honors the equals/hashCode contract in a degenerate way by returning a constant. This would make the hashCode method essentially useless and make Area objects nearly useless as keys in a HashMap or Hashtable.

或其他修改 equals(Area) 行为的方法,这些行为会改变其语义或使其与 hashCode 不一致。

看起来维护者认为更改此方法既不可行(因为错误评论中概述的选项都不能完全解决问题)也不重要(因为实施的方法非常慢,可能只会正如评论者所建议的那样,在将 Area 的实例与其自身进行比较时,永远 return 为真。