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 はマッチャーでのみ一致を呼び出すことがわかりました。

この場合の Match メソッドは次のとおりです。

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か?クラスでオーバーライドequalsしていないPermutationため、デフォルトで参照 ID が使用されます。順列に関しては、等価とは何を意味するのかを示すためにオーバーライドする必要があります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(これに対応する方法でオーバーライドする必要もあります。)

さらに:

  • が nullの場合を考慮するかelements、コンストラクターで検証します。
  • 平等は最終クラスで定義するのが最も簡単です
  • リストの防御的なコピーを作成していないため、構築後に呼び出し元によって変更される可能性があります。たとえば、順列をマップのキーとして使用すると、問題が発生する可能性があります。
于 2011-12-12T05:57:25.253 に答える