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

时间:2015-02-17 14:08:20

标签: java 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源代码中看到,equalsArea方法的签名如下所示:

public boolean equals(Area other)

请注意,{em>不是 @Override来自equals的普通Object方法,而只是使用更具体的类型重载方法。因此,上面示例中的两个调用最终会调用equals的不同实现。

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

我唯一的猜测是,作者担心在equalsArea等中放置Set时,区域的Map实施缓慢不适合比较相等性。数据结构。 (在上面的示例中,您可以将a添加到HashSet,虽然b等于a,但调用contains(b)将失败。)然后再次,为什么他们不仅仅以不与equals方法这样的基本概念冲突的方式命名可疑方法?

2 个答案:

答案 0 :(得分:4)

RealSkeptic在上面的评论中与JDK-4391558相关联。该错误中的comment解释了推理:

  

重写equals(Object)的问题是你也必须这样做   覆盖hashCode()以返回保证equals()的值   仅当两个对象的哈希码相同时才为真。

但:

  

这里的问题是Area.equals(Area)不能执行   直截了当的比较。它精心检查每一个   两个区域中的几何体并测试它们是否覆盖了   相同的封闭空间。两个Area对象可以完全拥有   相同封闭空间和等于(面积)的不同描述   会发现它们是一样的。

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

  

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

或:

  

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

或:

  

实现equals(Object)来调用equals(Area)并实现一个虚拟   hashCode()以简并中的方式表示equals / hashCode契约   通过返回常量的方式。这将构成hashCode方法   基本没用,并使Area对象几乎无用作为a中的键   HashMap或Hashtable。

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

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

答案 1 :(得分:0)

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

因为参数具有不同类型的重载方法不需要覆盖。

  

重写方法与父类中的方法具有完全相同的方法名称,返回类型,参数数量和参数类型,唯一的区别是方法的定义。

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

  

1。)方法的参数数量不同。

     

2。)参数类型不同(比如将float的参数更改为int)。

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

因为这会让人们闯入未来。如果我们有90年代的时间机器,我们可以在没有这个问题的情况下完成它。