为equals()实现选择字段的最佳实践 [英] Best practice to choose fields for equals() implementation

查看:107
本文介绍了为equals()实现选择字段的最佳实践的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在编写单元测试时,我经常遇到以下情况:测试中某些对象的 equals()-在 assertEquals -应该与实际环境中的工作方式不同。以某些接口 ReportConfig 为例。它具有 id 和其他几个字段。逻辑上,当它们的 id 匹配时,一个配置等于另一个。但是在测试某些特定的实现时,例如 XmlReportConfig ,显然我想匹配所有字段。一种解决方案是不要在测试中使用 equals 并仅遍历对象属性或字段并进行比较,但这似乎不是一个好的解决方案。

When writing unit-tests, I often face the situation when equals() for some object in tests -- in assertEquals -- should work differently from how it works in actual environment. Take for example some interface ReportConfig. It has id and several other fields. Logically, one config equals to another one when their ids match. But when it comes to testing some specific implementation, say, XmlReportConfig, obviously I want to match all fields. One solution is not to use equals in tests and just iterate over the object properties or fields and compare them, but it doesn't seem like a good solution.

因此,除了这种特殊情况外,我想从语义上而不是从技术上梳理实现平等的最佳实践。

So, apart from this specific type of situations, I want to sort out what are best practices to implement equals, semantically, not technically.

推荐答案


在语义上而非技术上实现平等的最佳实践是什么。

what are best practices to implement equals, semantically, not technically.

在Java中,等于方法实际上应被视为身份等于 是因为它如何与 Collection Map 实现。请考虑以下内容:

In Java the equals method really should be considered to be "identity equals" because of how it integrates with Collection and Map implementations. Consider the following:

 public class Foo() {
    int id;
    String stuff;
 }

 Foo foo1 = new Foo(10, "stuff"); 
 fooSet.add(foo1);
 ...
 Foo foo2 = new Foo(10, "other stuff"); 
 fooSet.add(foo2);

如果 Foo 身份是 id 字段,然后第二个 fooSet.add(...)应该 Set ,但应返回 false ,因为 foo1 foo2 具有相同的 id 。如果定义 Foo.equals (和hashCode)方法以同时包含 id stuff 字段,则此字段可能会被破坏,因为 Set 可能包含2个对具有相同id字段的对象的引用。

If Foo identity is the id field then the 2nd fooSet.add(...) should not add another element to the Set but should return false since foo1 and foo2 have the same id. If you define Foo.equals (and hashCode) method to include both the id and the stuff fields then this might be broken since the Set may contain 2 references to the object with the same id field.

如果您没有将对象存储在 Collection (或 Map ),则不必以这种方式定义 equals 方法,但是许多人认为它是错误的形式。如果将来您要做将其存储在 Collection 中,那么事情将会崩溃。

If you are not storing your objects in a Collection (or Map) then you don't have to define the equals method this way, however it is considered by many to be bad form. If in the future you do store it in a Collection then things will be broken.

如果我需要测试所有字段的相等性,我倾向于编写另一种方法。像 equalsAllFields(Object obj)之类的东西。

If I need to test for equality of all fields, I tend to write another method. Something like equalsAllFields(Object obj) or some such.

然后,您将执行以下操作:

Then you would do something like:

assertTrue(obj1.equalsAllFields(obj2));

此外,正确的做法是定义等于方法,该方法考虑了可变字段。当我们开始谈论类层次结构时,这个问题也变得很困难。如果子对象将 equals 定义为其本地字段的基类 equals 然后违反了它的对称性:

In addition, a proper practice is to not define equals methods which take into account mutable fields. The problem also gets difficult when we start talking about class hierarchies. If a child object defines equals as a combination of its local fields and the base class equals then its symmetry has been violated:

 Point p = new Point(1, 2);
 // ColoredPoint extends Point
 ColoredPoint c = new ColoredPoint(1, 2, Color.RED);
 // this is true because both points are at the location 1, 2
 assertTrue(p.equals(c));
 // however, this would return false because the Point p does not have a color
 assertFalse(c.equals(p));

更多阅读我强烈建议阅读陷阱3:根据可变字段定义等式中的部分。

Some more reading I would highly recommend is the "Pitfall #3: Defining equals in terms of mutable fields" section in this great page:


如何在Java中编写平等方法

一些其他链接:

  • Implementing hashCode() and equals()
  • Graceful Blog - Values, Equals, and Hashcodes

哦,只是为了后代,无论您选择比较哪些字段来确定相等性,都需要在 hashCode 计算中使用相同的字段。 等于 hashCode 必须对称。如果两个对象相等,则它们必须具有相同的哈希码。相反不一定是正确的。

Oh, and just for posterity, regardless of what fields you choose to compare to determine equality, you need to use the same fields in the hashCode calculation. equals and hashCode must be symmetric. If two objects are equals, they must have the same hash-code. The opposite is not necessarily true.

这篇关于为equals()实现选择字段的最佳实践的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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