编辑:事情的核心
当传统的equals方法的其余部分失败时,Identity Test何时通过?这是为了节省额外工作的时间吗?
原帖
我在我正在测试的课程中使用CompareToBuilder中的org.apache.commons.lang3.builder.CompareToBuilder。我注意到EqualsBuilder要求在调用equals构建器之前显式调用以下代码。
if (obj == this) { return true; } // Identity test
这种逻辑也出现在Eclipse自动生成的equals方法中。我正在尝试使用DRY方法,让我的equals
方法只需调用我的compareTo
方法并将等效性测试为0。
一个问题是我是否需要在我的equals方法中包含上述代码,将其添加到我的compareTo方法中,或者是否已由CompareToBuilder覆盖。我注意到CompareToBuilder检查传递的参数的等价性,但是没有接收到对原始lhs(this)和rhs(Object obj)的任何直接引用。这让我认为这是一个疏忽,我应该在compareTo方法中纠正。
我最大的问题是我似乎无法设计一个潜在的测试用例obj == this
但是this.compareTo(obj) != 0
。只有想到的事情是在一个未正确实现的比较中如果没有首先检查this
中的相应变量是否也为空,则在obj中发送其实例变量之一null可能会返回非零数字。 (昨天进入这个。)
示例等于方法:
@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();
}
答案 0 :(得分:3)
查看Comparable
的文档,compareTo()
需要
x.compareTo(y) == -y.compareTo(x)
因此,如果是x == y
,x.compareTo(x) == -x.compareTo(x)
,那么x.compareTo(x) == 0
。因此,x == y && x.compareTo(y) != 0
的唯一方法是打破compareTo()
合同。
请注意,在我的理解中,obj == this
测试往往被添加到equals()
方法作为优化,以防止在不必要时评估深度比较并且不影响调用的结果。 (参见Effective Java 2nd Ed,Item 8.)我假设这里的compareTo()
方法也是如此。
答案 1 :(得分:1)
当传统的equals方法的其余部分失败时,Identity Test何时通过?这是为了节省额外工作的时间吗?
简短的回答是:永远不会。
身份测试是一种廉价的优化,旨在快速解决equals()方法的其他问题。实际上,Joshua Bloch建议每个equals()方法都以优化测试开始(Effective Java,2nd Ed。)。
先生。 Bloch建议使用equals()的以下一般结构:
使用==运算符检查参数是否是对此对象的引用。如果是,则返回true。
使用instanceof运算符检查参数的类型是否正确。如果不是,则返回false。
将参数转换为正确的类型。
对于类中的每个重要字段,检查参数的该字段是否与此对象的相应字段匹配。
等
答案 2 :(得分:1)
当传统的等于失败时,身份测试何时通过?
从技术上讲,如果“传统”也意味着“天真”,那么带有循环的对象图(例如A有一个指向B的ivar,其中有一个指向A的ivar)会通过身份测试,但是传统的等于实现将进入无限循环。
我不确定Apache库是否可以防止这种情况。