7

についてのドキュメントjava.util.Set.contains(Object o)は言う:

このセットに(o == null?e == null:o.equals(e))のような要素eが含まれている場合にのみtrueを返します。

そうは言っても、ここにPOJOがあります(ご覧のとおり、私はそのequalsメソッドを上書きしました):

public class MonthAndDay {

    private int month;
    private int day;

    public MonthAndDay(int month, int day) {
        this.month = month;
        this.day = day;
    }

    @Override
    public boolean equals(Object obj) {
        MonthAndDay monthAndDay = (MonthAndDay) obj;
        return monthAndDay.month == month && monthAndDay.day == day;
    }

}

では、なぜ次のコードがfalse代わりに出力されるのtrueですか?

Set<MonthAndDay> set = new HashSet<MonthAndDay>();
set.add(new MonthAndDay(5, 1));
System.out.println(set.contains(new MonthAndDay(5, 1)));
// prints false

解決策はメソッドを書き直すことですcontains(Object o)が、元のメソッドは(ほぼ)まったく同じである必要があります、私は間違っていますか?

Set<MonthAndDay> set = new HashSet<MonthAndDay>() {

    private static final long serialVersionUID = 1L;

    @Override
    public boolean contains(Object obj) {
        MonthAndDay monthAndDay = (MonthAndDay) obj;
        for (MonthAndDay mad : this) {
            if (mad.equals(monthAndDay)) {
                return true;
            }
        }
        return false;
    }

};
set.add(new MonthAndDay(5, 1));
System.out.println(set.contains(new MonthAndDay(5, 1)));
// prints true
4

2 に答える 2

15

オーバーライドするときはequals(Object)、もオーバーライドする必要がありますhashcode()

具体的には、メソッドは、が、の場合a.equals(b)はすべてになるように実装する必要があります。この不変条件が尊重されない場合、、、およびは正しく機能しません。truea.hashcode() == b.hashcode()trueHashMapHashSetHashtable

hashcode()動作方法と動作の技術的な詳細は、ObjectAPIequals(Object)で指定されています。


では、これを間違えると、なぜハッシュベースのデータ構造が壊れるのでしょうか。基本的に、ハッシュテーブルは、ハッシュ関数の値を使用して、「候補」と比較する値のセットを絞り込むことによって機能するためです。候補のハッシュコードがテーブル内の一部のオブジェクトのハッシュコードと異なる場合、オブジェクトが等しい場合でも、ルックアップアルゴリズムがテーブル内のオブジェクトと比較されない可能性があります。

于 2012-09-03T13:59:46.223 に答える
6

HashSet要素が同じを共有するequals() 場合にのみ使用されるためhashCode()、両方をオーバーライドする必要があります。によって使用されるコードの関連部分は次のとおりです(に裏打ちされているHashSet#contains()ことに注意してください):HashSetHashMap

  355       /**
  356        * Returns the entry associated with the specified key in the
  357        * HashMap.  Returns null if the HashMap contains no mapping
  358        * for the key.
  359        */
  360       final Entry<K,V> getEntry(Object key) {
  361           int hash = (key == null) ? 0 : hash(key.hashCode());
  362           for (Entry<K,V> e = table[indexFor(hash, table.length)];
  363                e != null;
  364                e = e.next) {
  365               Object k;
  366               if (e.hash == hash &&
  367                   ((k = e.key) == key || (key != null && key.equals(k))))
  368                   return e;
  369           }
  370           return null;
  371       }

そうしないと、の契約に違反Object#hashCode()します。

メソッドに従って2つのオブジェクトが等しい場合、2つのオブジェクトのそれぞれでメソッドequals(Object)を呼び出すとhashCode、同じ整数の結果が生成される必要があります。

于 2012-09-03T13:59:07.113 に答える