为什么Java的Area#equals方法不会覆盖Object#equals? [英] Why does Java's Area#equals method not override Object#equals?

查看:157
本文介绍了为什么Java的Area#equals方法不会覆盖Object#equals?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I just ran into a problem caused by Java's java.awt.geom.Area#equals(Area) method. The problem can be simplified to the following unit test:

@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源代码中看到了 Area 等于方法的签名如下所示:

After some head scratching and debugging, I finally saw in the JDK source, that the signature of the equals method in Area looks like this:

public boolean equals(Area other)

注意从 @Override 正常的等于方法对象,而只是使用更具体的类型重载方法。因此,上面示例中的两个调用最终调用等于的不同实现。

Note that it does not @Override the normal equals method from Object, but instead just overloads the method with a more concrete type. Thus, the two calls in the example above end up calling different implementations of equals.

由于此行为已被从Java 1.2开始,我认为它不被认为是一个bug。因此,我更感兴趣的是找出为什么决定正确覆盖等于方法,但同时提供一个超载的变种。 (另一个提示,这是一个真正的决定是没有覆盖 hashCode()方法。)

As this behavior has been present since Java 1.2, I assume it is not considered a bug. I am, therefore, more interested in finding out why the decision was made to not properly override the equals method, but at the same time provide an overloaded variant. (Another hint that this was an actual decision made is the absence of an overwritten hashCode() method.)

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

My only guess would be that the authors feared that the slow equals implementation for areas is unsuitable for comparing equality when placing Areas in Set,Map,etc. datastructures. (In the above example, you could add a to a HashSet, and although b is equal to a, calling contains(b) will fail.) Then again, why did they not just name the questionable method in a way that does not clash with such a fundamental concept as the equals method ?

推荐答案

RealSkeptic链接到 JDK-4391558 在上面的评论中。在评论解释了推理:

RealSkeptic linked to JDK-4391558 in a comment above. The comment in that bug explains the reasoning:


覆盖equals(Object)的问题是你还必须
重写hashCode()以返回一个值,该值保证equals()
只有在两个对象的哈希码相等时才为真。

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.

但是:


这里的问题是Area.equals(Area)不执行一个非常
的直接比较。它仔细检查了两个区域中每一块
的几何形状,并测试它们是否覆盖
相同的封闭空间。两个Area对象可以具有相同封闭空间的完全
不同描述,而equals(Area)
将检测到它们是相同的。

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.

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

So basically we're left with an array of not-so-pleasant options, such as:


弃用等于(区域)并为该
操作创建备用名称,例如areasEqual,以避免混淆。
不幸的是,旧方法将保留并且可以链接,
会捕获许多打算调用equals(Object)
版本的人。

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.

或:


弃用等于(Area)并将其实现更改为$
equals(Object),以便在调用错误的
方法时避免语义问题。创建一个具有不同名称的新方法,以避免
混淆,以实现equals(Area)提供的旧功能。

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).

或者:


实现equals(Object)调用equals(Area)并实现一个虚拟的
hashCode()来表示等于/ hashCode通过返回常量以简并
方式收缩。这会使hashCode方法
基本无用,并使得Area对象几乎无用作
HashMap或Hashtable中的键。

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.

或修改等于(Area)行为的其他方法,这些行为会改变其语义或使其与 hashCode

or other ways to modify the equals(Area) behavior that would either change its semantics or make it inconsistent with hashCode.

看起来维护人员认为改变这种方法既不可行(因为bug评论中没有提出任何选项可以解决问题)也不重要(因为实现时,该方法非常慢,并且在将 Area 的实例与其自身进行比较时可能只返回true,如评论者所建议的那样。

Looks like changing this method is deemed by the maintainers to be neither feasible (because neither option outlined in the bug comment quite solves the problem) nor important (since the method, as implemented, is quite slow and would probably only ever return true when comparing an instance of an Area with itself, as the commenter suggests).

这篇关于为什么Java的Area#equals方法不会覆盖Object#equals?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆