2

为作业创建测试,我遇到了一个奇怪的AssertionError异常。

我已经改变了它,直到我遇到一个简单的案例:

List<Integer> elements= new ArrayList<Integer>();
elements.add(1);
elements.add(2);
elements.add(3);

Permutation p2 = new Permutation(elements);
Permutation p1 = new Permutation(elements);

assertThat(p2, equalTo(p1));

排列.java:

public class Permutation {

  private List<Integer> elements;

  public Permutation(List<Integer> elements) {
    this.elements = elements;
  }

public boolean equals(Permutacion permutation){
  if ( this.elements.size() != permutation.elements.size()){
    return false;
  }

  Iterator<Integer> iterThis = this.elements.iterator();
  Iterator<Integer> iterOther = permutation.elements.iterator();
  while ( iterThis.hasNext() && iterOther.hasNext()){
    if ( iterThis.next() != iterOther.next()){
      return false;
    }
  }

  return true;

}

挖掘 junit 和 hamcrest 源代码,我发现 junit assertThat 只调用匹配器上的匹配项。

在这种情况下,matches 方法是:

public boolean matches(Object arg) {
    return areEqual(arg, object);
}

private static boolean areEqual(Object o1, Object o2) {
    if (o1 == null) {
        return o2 == null;
    } else if (o2 != null && isArray(o1)) {
        return isArray(o2) && areArraysEqual(o1, o2);
    } else {
        return o1.equals(o2);
    }
}

其中 arg 应为“p2”,object 应为“p1”。

(可以在Hamcrest 存储库中浏览)

areEqual 方法中使用调试器检查的比较结果是:

"p2 == null"                    false   
"p1 != null"                    true    
"p2.getClass().isArray()"       false   
"p2.equals(p1)"                 true    
"equalTo(p1).matches(p2)"       false   

如您所见,代码应该达到最后一个 else 条件并返回true( p2.equals(p1)),但equalTo(p1).matches(p2)返回false

谢谢你的帮助

4

1 回答 1

7

你为什么会期待p2.equals(p1)回来true?您尚未equalsPermutation类中覆盖,因此默认情况下它将使用引用标识。当涉及到排列时,您需要覆盖equals(并且hashCode,通常,匹配等于)以指示相等的含义。

编辑:现在您发布了更多代码,更清楚发生了什么。您的 equals 方法具有以下签名:

public boolean equals(Permutacion permutation){

不会覆盖Object.equals,这是匹配器将使用的。相反,它重载了它 - 引入了一种新方法,这是在调试器检查中调用的方法。如果你写:

Object o1 = p1;

然后p2.equals(o1)也会false在调试器中显示 - 这实际上就是匹配器正在做的事情。您的 equals 方法应类似于:

@Override
public boolean equals(Object other)
{
    if (other == null || other.getClass() != this.getClass())
    {
        return false;
    }
    Permutation otherPermutation = (Permutation) other;

    // List.equals should do the right thing here
    return elements.equals(otherPermutation.elements);
}

(您还应该hashCode以与此相对应的方式覆盖。)

此外:

  • elements要么考虑为空的情况,要么在构造函数中验证它
  • 在最终类中定义平等是最简单的
  • 由于您没有制作列表的防御性副本,因此调用者可能会在构建后对其进行突变;例如,如果您曾经将排列用作映射中的键,这可能会导致问题。
于 2011-12-12T05:57:25.253 回答