日々常々

ふつうのプログラマがあたりまえにしたいこと。

HashSetでequalsとhashCodeを使った問題

以下のコードを実行したらどうなるか。

(1)

Set set = new HashSet();
set.add(new Object());
set.add(new Object());

System.out.println(set.size());

(2)

class A {
    public boolean equals(Object obj) {throw new RuntimeException();}
}
Set set = new HashSet();
set.add(new A());
set.add(new A());

System.out.println(set.size());

(3)

class A {
    public int hashCode() {return 1;}
}
Set set = new HashSet();
set.add(new A());
set.add(new A());

System.out.println(set.size());

(4)

class A {
    public boolean equals(Object obj) {return true;}
    public int hashCode() {return 1;}
}
class B {
    public boolean equals(Object obj) {return true;}
    public int hashCode() {return 1;}
}

Set set = new HashSet();
set.add(new A());
set.add(new A());
set.add(new B());

System.out.println(set.size());


答え

  • (1)2
  • (2)2
  • (3)2
  • (4)1

わかる人には問題にすらならないんだよね。要するに「hashCodeが一致してequalsがtrueを返すものは同じものとして扱われる」ってだけです。hashCodeが一致しなきゃそもそもequalsなんて評価もされない。よくわからない人はJDKのコード読めばわかると思います。ついでにHashSetの中身はHashMapだってことも判るかも知れません。
hashCodeはハッシュテーブルで使われますが、これが何ものかを簡単に言うと、対象を絞り込むために使うようなものです。無理矢理現実に当てはめると、郵便番号や市外局番とかをイメージすると良いかもしれません。同じ郵便番号に複数の家があるように、同じhashCodeを持つ複数のオブジェクトが存在しえます。
hashCodeを使用する場合、まずhashCodeで絞り込んでからequalsで比較する事になります。これはhashCodeが十分に分散していたり、大量のオブジェクトが対象だったり、equalsの処理が重かったりする時に有効な手段になります。


当たり前のことを説明してみてボロが出ないか確認してみる。たぶん大丈夫だよね…。