5

Java にVertexは、Java3D クラスのサブクラスがありPoint3fます。座標の値に基づいてPoint3f計算するようになりましたが、私のクラスではより厳密にしたいと考えています。2 つの頂点が等しいのは、それらが同じオブジェクトである場合のみです。ここまでは順調ですね:equals()Vertex

class Vertex extends Point3f {

    // ...

    public boolean equals(Object other) {
        return this == other;
    }
}

これが の契約に違反していることはわかってequals()いますが、頂点を他の頂点と比較するだけなので、これは問題ではありません。

ここで、頂点を に配置できるようにするにHashMapは、hashCode()メソッドは と一致する結果を返さなければなりませんequals()。現在それを行っていますが、おそらく戻り値は のフィールドに基づいているため、同じ座標を持つPoint3f異なるオブジェクトに対してハッシュ衝突が発生します。Vertex

したがって、のフィールドhashCode()から計算するのではなく、オブジェクトのアドレスに基づいて を使用したいと思います。クラスがこれを行うことはVertex知っていますが、メソッドをオーバーライドするため、そのメソッドを呼び出すことはできません。ObjecthashCode()Point3f

だから、実際に私の質問は2つあります:

  • 私はそのような浅いものが欲しいequals()ですか?
  • はいの場合、ハッシュコードを計算するためのオブジェクトのアドレスを取得するにはどうすればよいですか?

編集:私は何かを考えました...intオブジェクトの作成時にランダムな値を生成し、それをハッシュコードに使用できます。それは良い考えですか?なぜだめですか)?

4

7 に答える 7

10

System.identityHashCode() を使用するか、IdentityHashMap を使用してください。

于 2008-09-24T18:29:26.190 に答える
1

System.identityHashCode()hashCode()指定されたオブジェクトのクラスがオーバーライドするかどうかに関係なく、デフォルト メソッドによって返されるものと同じハッシュ コードを指定されたオブジェクトに返しますhashCode()

于 2008-09-24T18:31:13.113 に答える
0

そもそもなぜ hashCode() をオーバーライドしたいのですか? 他の平等の定義で作業したい場合は、それを行いたいと思うでしょう。例えば

パブリック クラス A { int id;

public boolean equals(A other) { return other.id==id} public int hashCode() {return id;}

IDが同じであればオブジェクトも同じであり、これを行うことができないようにハッシュコードをオーバーライドすることを明確にしたい場合:

HashSet ハッシュ = 新しい HashSet(); hash.add(新しい A(1)); hash.add(新しい A(1)); 2つの同一の(平等の定義の観点から)Aを取得します。正しい動作は、ハッシュにオブジェクトが 1 つしかなく、2 番目の書き込みで上書きされることです。

于 2008-09-24T19:43:44.297 に答える
0

この答えはおそらくより良いですが、デリゲートを使用します。


class Vertex extends Point3f{
   private final Object equalsDelegate = new Object();
   public boolean equals(Object vertex){
      if(vertex instanceof Vertex){
         return this.equalsDelegate.equals(((Vertex)vertex).equalsDelegate);
      }
      else{
         return super.equals(vertex);
      }
   }
   public int hashCode(){
      return this.equalsDelegate.hashCode();
   }
}
于 2008-09-24T18:38:51.347 に答える
0

equals を論理比較ではなく物理比較 (つまり、同じオブジェクト) として使用しているため、ハッシュコードが一意の値を返すことを保証する唯一の方法は、独自の提案のバリエーションを実装することです。乱数を生成する代わりに、UUID を使用して各オブジェクトの実際の一意の値を生成します。

ほとんどの場合、 System.identityHashCode() は機能しますが、 Object.hashCode() メソッドがすべてのオブジェクトに対して一意の値を返すことが保証されていないため、保証されていません。限界的なケースが発生するのを見てきましたが、それはおそらく VM の実装に依存することになるでしょう。これは、コードを依存させたいものではありません。

Object.hashCode() の javadoc からの抜粋: 合理的に実用的である限り、クラス Object によって定義された hashCode メソッドは、個別のオブジェクトに対して個別の整数を返します。(これは通常、オブジェクトの内部アドレスを整数に変換することによって実装されますが、この実装手法は JavaTM プログラミング言語では必要ありません。)

これが対処する問題は、2 つの別々のポイント オブジェクトがハッシュマップに挿入されたときに、それらが同じハッシュを持っているために互いに上書きされない場合です。hashCode() のオーバーライドを伴う論理的な等号がないため、identityHashCode メソッドによって実際にこのシナリオが発生する可能性があります。論理ケースが同じ論理ポイントのハッシュ エントリのみを置き換える場合、システム ベースのハッシュを使用すると、任意の 2 つのオブジェクトでそれが発生する可能性があり、等価性 (さらにはクラス) はもはや要因ではありません。

于 2008-09-24T22:43:23.600 に答える
0

参考までに、あなたのequalsメソッドはequalsコントラクトに違反していません(つまり、ベースオブジェクトのコントラクトの場合)...これは基本的にベースオブジェクトメソッドのequalsメソッドであるため、Vertex equalsの代わりにidentity equalsが必要な場合は、大丈夫。

ハッシュ コードに関しては、実際に変更する必要はありませんが、受け入れられた回答は適切なオプションであり、ハッシュ テーブルに同じ値を持つ多数の頂点キーが含まれている場合ははるかに効率的です。

変更する必要がない理由は、ハッシュコードが false を返すオブジェクトに対して同じ値を返すことはまったく問題ないためです... EVERY に対して常に 0 を返すだけの有効なハッシュコードですらあります実例。これがハッシュ テーブルに対して効率的であるかどうかは、まったく別の問題です...多くのオブジェクトが同じハッシュ コードを持っている場合、より多くの衝突が発生します (これは、ハッシュ コードをそのままにして多くの頂点を持っていた場合に発生する可能性があります)同じ値で)。

もちろん、これを答えとして受け入れないでください(あなたが選んだものははるかに実用的です)、ハッシュコードとイコールに関する背景情報をもう少し提供したかっただけです;-)

于 2008-09-24T18:44:10.350 に答える
-2

関数 hashCode() は Object から継承され、(座標レベルではなくオブジェクト レベルで) 意図したとおりに機能します。変更する必要はありません。

equals-method については、コードで obj1 == obj2 を使用する代わりに equals を使用できるため、使用する理由はありません。これは、座標の比較がはるかに理にかなっているソートなどを目的としているためです。

于 2008-09-24T18:27:14.683 に答える