0

编辑:问题的核心

身份测试何时通过,传统的 equals 方法的其余部分何时失败?这只是为了节省做额外工作的时间吗?


原帖

我正在测试的类中使用来自org.apache.commons.lang3.builder.CompareToBuilder的CompareToBuilder 。我注意到EqualsBuilder需要在调用 equals 构建器之前显式调用以下代码。

if (obj == this) { return true; } // Identity test

这样的逻辑也出现在 Eclipse 自动生成的 equals 方法中。我试图通过让我的方法简单地调用我的方法并将等效性测试为 0来使用DRY方法。equalscompareTo

一个问题是我是否需要在我的 equals 方法中包含上面的代码,将它添加到我的 compareTo 方法中,或者它是否已经被CompareToBuilder覆盖。我注意到CompareToBuilder检查传递的参数的等效性,但没有收到对原始 lhs(this)和 rhs(Object obj)的任何直接引用。这使我认为这是我应该在 compareTo 方法中纠正的疏忽。

我最大的问题是我似乎无法设计一个潜在的测试用例,obj == thisthis.compareTo(obj) != 0. 唯一想到的是在一个不正确实现的 compareTo 中,如果没有首先检查相应的变量 inthis是否也为 null,则发送带有其实例变量之一 null 的 obj 可能会返回一个非零数。(昨天碰到这个)。

样本等于方法:

@Override
public boolean equals(Object obj) {
    if (obj != null && obj instanceof MyClass)
        return this.compareTo((MyClass)obj) == 0;
    return false;
}

示例 compareTo 方法

@Override
public int compareTo(MyClass other) {
return new CompareToBuilder()
    .append(this.getParam1(), other.getParam1())
    .append(this.getParam2(), other.getParam2())
    .toComparison();
}
4

3 回答 3

3

在文档中查找ComparablecompareTo()需要

x.compareTo(y) == -y.compareTo(x)

因此,如果x == yx.compareTo(x) == -x.compareTo(x)x.compareTo(x) == 0。所以唯一的办法x == y && x.compareTo(y) != 0就是打破compareTo()合同。

请注意,在我的理解中,obj == this测试倾向于equals()作为一种优化添加到方法中,以防止在不必要且不影响调用结果的情况下评估深度比较。compareTo()(参见 Effective Java 2nd Ed,Item 8。)我假设这里的方法也是如此。

于 2013-05-30T21:35:48.090 回答
1

身份测试何时通过,传统的 equals 方法的其余部分何时失败?这只是为了节省做额外工作的时间吗?

简短的回答是:从不。

身份测试是一种廉价的优化,旨在快速摆脱equals() 方法的其余部分。事实上,Joshua Bloch 建议每个 equals() 方法都从优化之类的测试开始(Effective Java,第 2 版)。

Bloch 先生建议 equals() 采用以下一般结构:

  1. 使用 == 运算符检查参数是否是对该对象的引用。如果是,则返回 true。

  2. 使用 instanceof 运算符检查参数的类型是否正确。如果不是,则返回false。

  3. 将参数转换为正确的类型。

  4. 对于类中的每个重要字段,检查参数的该字段是否与该对象的相应字段匹配。

  5. 等等。

于 2013-05-30T22:17:31.210 回答
1

当传统的 equals 失败时,身份测试何时通过?

从技术上讲,如果“传统”也意味着“天真”,那么其中包含循环的对象图(例如,A 有一个指向 B 的 ivar,而 B 有一个指向 A 的 ivar)将通过身份测试,但传统的等于实现将进入无限循环。

我不确定 Apache 库是否可以防止这种情况发生。

于 2013-05-31T16:44:39.457 回答