22
class temp {
int id;

public int getId() {
  return id;
}

temp(int id) {
  this.id = id;
}

public void setId(int id) {
  this.id = id;
}

@Override
public boolean equals(Object obj) {
  if (this == obj)
      return true;
  if (obj == null)
      return false;
  if (getClass() != obj.getClass())
      return false;
  temp other = (temp) obj;
  if (id != other.id)
      return false;
  return true;
}
}

public class testClass {

    public static void main(String[] args) {
      temp t1 = new temp(1);
      temp t2 = new temp(1);
      System.out.println(t1.equals(t2));
      Set<temp> tempList = new HashSet<temp>(2);
      tempList.add(t1);
      tempList.add(t2);
      System.out.println(tempList);
}

プログラムは両方の要素をセットに追加します。setにメソッドを追加しているときに、equalsメソッドが呼び出されるので、最初はショックを受けました。

しかし、それから私はhashCodeメソッドを無効にしました:

@Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + id;
        return result;
    }

そして、それは追加されませんでした。Setとadd()メソッドのJavadocは、Setに追加するときにequals()のみをチェックすると言っているので、これは驚くべきことです。

そしてこれはadd()のjavadocです:

/**
     * Adds the specified element to this set if it is not already present.
     * More formally, adds the specified element <tt>e</tt> to this set if
     * this set contains no element <tt>e2</tt> such that
     * <tt>(e==null&nbsp;?&nbsp;e2==null&nbsp;:&nbsp;e.equals(e2))</tt>.
     * If this set already contains the element, the call leaves the set
     * unchanged and returns <tt>false</tt>.
     *
     * @param e element to be added to this set
     * @return <tt>true</tt> if this set did not already contain the specified
     * element
     */
    public boolean add(E e) {
      return map.put(e, PRESENT)==null;
    }

次に、HashSetがHashMapとして実装されており、マップではオブジェクトのhashCodeがキーとして使用されていることに気付きました。したがって、hashCodeをオーバーライドしない場合は、異なるキーを使用してそれらを処理します。

これは、add()メソッドまたはHashSetのドキュメントに含めるべきではありませんか?

4

4 に答える 4

20

それは一種の文書化されています。次のように記載されているjava.lang.Objectのドキュメントを参照してくださいhashCode()

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

Object.equals(Object)さらに、メソッドのドキュメントには次のことが記載されています。

通常、このメソッドがオーバーライドされるときは常に hashCode メソッドをオーバーライドする必要があることに注意してください。これは、等しいオブジェクトには等しいハッシュ コードが必要であるという hashCode メソッドの一般的な契約を維持するためです。

言い換えれば、あなたのクラスでいつinstanceA.equals(instanceB) == trueそしてinstanceA.hashCode() != istanceB.hashCode()あなたが実際に Object クラスの契約に違反している場合.

于 2012-06-20T07:24:53.387 に答える
14

equals()ドキュメントもご覧ください。

通常、このメソッドがオーバーライドされるときは常に hashCode メソッドをオーバーライドする必要があることに注意してください。これは、等しいオブジェクトには等しいハッシュ コードが必要であるという hashCode メソッドの一般的な契約を維持するためです。

実はequals()hashCode()は強く結びついています。これらの一貫性の問題を回避するために、いずれかを使用する場合は常に両方を考慮する必要があります。

于 2012-06-20T07:25:53.730 に答える
8

equals() をオーバーライドする場合は、hashCode() もオーバーライドする必要があります。

オブジェクトのドキュメントに列挙されている equals() と hashCode() の動作にはいくつかの制限があります。特に、equals() メソッドは次のプロパティを示す必要があります。

  • 対称性: a と b の 2 つの参照の場合、b.equals(a) の場合にのみ a.equals(b)
  • 再帰性: すべての非 null 参照の場合、a.equals(a)
  • 推移性: a.equals(b) と b.equals(c) の場合、a.equals(c)
  • hashCode() との一貫性: 2 つの等しいオブジェクトは同じ hashCode() 値を持つ必要があります

詳しくはこちらをご覧ください。

于 2012-06-20T07:26:36.517 に答える
1

彼ら (javadoc 担当者) は、(add()メソッドのドキュメントでHashSet)

(e==null ? e2==null : e.equals(e2))

これhashCode()は本質的に両者にとって同等です。

于 2012-06-20T07:30:33.857 に答える