6

私はOCJP(旧SCJP)のために勉強していて、LinkedHashSetを使用する次の例に出くわしました:

public class Test{

    int size;

    public Test(int s){
       this.size = s;
    }

    @Override
    public boolean equals(Object obj) {
         return (this.size == ((Test)obj).size);
    }

    public static void main(String[] args) {
      LinkedHashSet<Test> s = new LinkedHashSet<Test>();
      s.add(new Test(1));
      s.add(new Test(2));
      s.add(new Test(1));
      System.out.println(s.size());
    }
}

ここで、問題は次の場合に表示される内容です:
1) 実装はそのまま
2) hashCode のオーバーライドがクラス Test に次のように挿入されます。

public int hashCode() {return size/5};

コードを実行してコンパイルすると、最初のケースでは set のサイズが 3 であるのに対し、2 番目のケースでは 2 であることが示されます。なぜですか?

ケース 1 では、equals メソッドはオーバーライドされますが、呼び出されることはありません。hashCode メソッドがオーバーライドされていない場合、add() メソッドはオブジェクトの等価性をチェックしないということですか?
ケース 2 では、指定された実装と指定された Test オブジェクトのセットを持つ hashCode は、常に同じ数値を返します。これはデフォルトの hashCode 実装とどのように違うのでしょうか? また、なぜ equals が呼び出されるのでしょうか?

4

2 に答える 2

10

をオーバーライドしない場合hashCode()、各インスタンスには、クラスで事前に定義されたハッシュ アルゴリズムから計算されたハッシュコードが含まれます。そのため、すべてのインスタンスが異なるハッシュコード値を持つ可能性があります (これは確実ではありません)。つまり、各インスタンスは独自のバケットに移動します。Object

equals()現在、何らかの属性に基づいて 2 つのインスタンスを等しくするメソッドをオーバーライドしたとしても、それらのハッシュコードは依然として異なります。

したがって、ハッシュコードが異なる 2 つのインスタンスが等しくなることはありません。したがって、セットのサイズは 3 です。重複がないためです。


ただし、次の実装でオーバーライドhashCode()すると: -

public int hashCode() {return size/5};

同じに対して同じ値を返しますsize。したがって、同じ値のインスタンスsizeは同じハッシュコードequalsを持ち、 に基づいてメソッドでそれらを比較したsizeため、それらは になりequal、したがってそれらはあなたの中で重複しているとSet見なされ、したがって削除されます.So,Set.size()は 2.

道徳: - 2 つのメソッド間の一般的な契約を維持するために、メソッドhashCode()をオーバーライドするときは常にオーバーライドする必要があります。equals()

hashcodeequals方法との間の一般契約: -

  • 2 つのオブジェクトが等しい場合、それらのハッシュコードは等しくなければなりません
  • 2 つのオブジェクトが等しくない場合、それらのハッシュコードは等しくなる可能性があります
  • hashCode アルゴリズムは、常に同じオブジェクトに対して同じ値を生成する必要があります。
  • 2 つのオブジェクトの hashCode が異なる場合、それらは等しくありません
  • 2 つのインスタンスを比較するために使用same attributesした計算に常に使用します。hashCode

少なくとも一度は読むことを強くお勧めします: -

于 2012-10-21T19:55:22.607 に答える
2

hashCode()ハッシュ構造は、Javaで表されるハッシュ アルゴリズムに依存します。何かを a HashMap(またはLinkedHashSetあなたの場合) に入れると、jvm はhashCode()、この構造に挿入されているオブジェクトを呼び出します。オーバーライドされていない場合、クラスのデフォルトhashCode()Object使用され、非効率的です。すべてのオブジェクトが独自のバケットに入ります。

例に示されている方法をオーバーライドするhashCode()と、例のすべてのオブジェクトが同じバケットに入ります。そして、(それらを次々に追加する場合)と比較されequals()ます。そのため、最初のケース (equals()が呼び出されていない場合) ではサイズが 3 になり、2 番目のケースではサイズが 2 になります。

于 2012-10-21T19:57:00.913 に答える