为什么Java';s面积#等于方法不覆盖对象#等于?
我刚刚遇到了一个由Java的为什么Java';s面积#等于方法不覆盖对象#等于?,java,equals,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)); // -&
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源代码中看到,区域中的等于方法的签名如下所示:
public boolean equals(Area other)
请注意,它不会从对象
覆盖正常的等于
方法,而只是使用更具体的类型重载该方法。因此,上面示例中的两个调用最终调用了equals
的不同实现
由于这种行为自Java1.2以来就一直存在,所以我假设它不被认为是一个bug。因此,我更感兴趣的是找出为什么决定不正确地重写equals
方法,但同时提供一个重载变量。(这是一个实际决定的另一个提示是缺少覆盖的hashCode()
方法。)
我唯一的猜测是,作者担心在将区域
放置在集合
,映射
等数据结构中时,区域的缓慢等于
实现不适合比较相等性。(在上面的示例中,您可以将a
添加到HashSet
,虽然b
等于a
,调用包含(b)
将失败。)那么,他们为什么不以一种与等于方法这样一个基本概念不冲突的方式命名有问题的方法呢?“为什么Java的Area#equals方法不重写Object#equals?”
因为重载方法不需要重写,因为重载方法的参数类型不同
重写的方法与父类中的方法具有完全相同的方法名称、返回类型、参数数量和参数类型,唯一的区别是方法的定义
本案并不强迫我们撤销,但它是超载的,因为它遵循以下规则:
1.)不同方法的参数数量不同
2.)参数类型不同(如将浮点参数更改为int)
“为什么他们不以一种与equals方法这样一个基本概念不冲突的方式命名这个有问题的方法?”
因为这可能会让人们走向未来。如果我们有一台90年代的时间机器,我们可以不用担心这个问题。上面的评论链接到Real怀疑论者。该错误中的错误解释了原因:
重写equals(Object)的问题是,您还必须
重写hashCode()以返回一个值,该值保证等于()
仅当两个对象的哈希代码也相等时,才为true
但是:
这里的问题是面积。等于(面积)不能执行非常简单的运算
直截了当的比较。它仔细地检查每一个
两个区域中的几何图形,并测试它们是否覆盖
相同的封闭空间。两个面积对象可以具有完全相同的
同一封闭空间的不同描述和相等(面积)
会发现它们是一样的
因此,基本上,我们只剩下一系列不太令人愉快的选择,例如:
弃用equals(Area)并为其创建一个备用名称
操作,如“areasEqual”,以避免混淆。
不幸的是,旧方法将保留下来,并且可以链接和使用
将诱捕许多打算调用equals(对象)的人
版本
或:
弃用equals(Area)并将其实现更改为
equals(Object)的用法,以避免错误时出现语义问题
方法。请使用其他名称创建新方法以避免
无法实现equals(Area)提供的旧功能
或:
实现equals(对象)以调用equals(区域)并实现虚拟
hashCode(),它在退化的
这将使hashCode方法
基本上是无用的,并使区域对象几乎无用的关键帧
哈希映射或哈希表
或者通过其他方式修改equals(Area)
行为,从而改变其语义或使其与hashCode
不一致
看起来,维护人员认为更改此方法既不可行(因为bug注释中列出的选项都不能完全解决问题),也不重要(因为该方法在实现时非常慢,并且可能只有在将区域的实例与自身进行比较时才会返回true,正如评论员所建议的)。注意hashCode
也没有被覆盖。我认为他们在这里所做的只是提供一个“比较”“恰好与Object.equals()同名的方法”
。就我个人而言,我会给它起一个不同的名字以避免混淆。Java API并不总是遵循最佳实践,这看起来像是一个疏忽。试着在Oracle开发人员电子邮件列表中提出这个问题,看看官方用词是什么。如果是疏忽,Sun/Oracle一直都不愿意让API改变nges发布后。这可能意味着它一开始是一个疏忽,导致它成为一个发布,现在只是冻结在时间上。看你误解了他的问题。问题是为什么你会重载它,而不是重写它。由@realponsult链接的错误提供了一些见解。@DeepakBala我指定了为什么你不重写它,以及如何重写它这个概念遵循重载规则。不确定你的意思,因为我似乎回答了这个问题,你能澄清一下吗?对不起,但正如我在问题中所说的,我非常清楚什么是重载和重载,以及何时可以使用它们。但是@