hashCode()メソッドがequals()は複数の独立した分野
質問
いクラスが平等に基づく2つの分野と合致し、この型のオブジェクトは等しいとみなされます。どのように書いてるんだhashCode()関数は、そのequals()の一般規約ではのハッシュコードが等しい場合、equalsはtrueを返します。
public class MyClass {
int id;
String name;
public boolean equals(Object o) {
if (!(o instanceof MyClass))
return false;
MyClass other = (MyClass) o;
if (other.id == this.id || other.name == this.name)
return true;
return false;
}
}
どうしてhashCode()機能でこのクラス?とは避けたいのは自明な場合はこちらの還元に一定のように:
public int hashCode() {
return 1;
}
解決
ないと思い、自明でないハッシュコードが存在します。また、お equals()
に違反する一般契約として に記載のAPI ---です ない他:
(1,2)
equals (1,3)
(4,3)
equals (1,3)
が (4,3)
は 等しくない へ (1,2)
.
請求項: このハッシュコードが必要にな定数です。
証:ましょう (a,b)
や (c,d)
きは、二つのオブジェクトが実際に異なるュー内、 h(a,b) ≠ h(c,d)
.を考慮するオブジェクト (a,d)
.のOPの定義 (a,d)
以 (a,b)
, は、 (a,d)
以 (c,d)
.以上からの hashcode契約 その h(a,d) = h(a,b) = h(c,d)
;は、矛盾に満ちているものです。
他のヒント
[OK]を、あなたのシナリオでは、第2のAPIの要件を無視して、何の非定数のハッシュ関数がありません。
のための異なる値を有するハッシュ関数があった想像
(B)、(C)、B!= C、次にハッシュ(B)!=ハッシュ(C)、筈(A、B)=(C)。
同様に、(B、A)と(C、A)同一のハッシュコードを発する必要があります。
私たちのハッシュ関数hを呼ぶことにしましょう。私たちは見つけます:
H(x、y)は、X、Y、V FORALL = hの(X、W)= hを(V、W)は、W
そこで、何をしたいんだけハッシュ関数は定数である。
私はザックの権利はかなり確信している - 。これを行うには非自明なハッシュコードはありません。
疑似証拠ます:
任意の二つの等しくない値を考慮して、X =(ID1、NAME1)及びY =(ID2、NAME2)。
今Z =(ID2、NAME1)を検討してください。これは、XとYの両方に等しく、したがってX及びYは、同じハッシュコード持っている必要があり、XおよびYの両方として同じハッシュコードを有していなければならない - 。全ての値が同じハッシュコードを持たなければならないことを意味します
あなたが対等の推移自然を破壊している -あなたは奇妙な状況に持っている理由があります。しかし、それはない - 。X.equals(Z)とZ.equals(Y)は、ががX.equals(Y)ことを意味すべきであるという事実平等のあなたの定義は、対等の通常の契約には適していません。
私はあなたがいないことができると思います。その理由は、あなたのequals()
方法は推移ではありません。
推移は、3つの非ヌルX、Y、Z、x.equals(y)
、y.equals(z)
、次いでx.equals(z)
場合ための手段。あなたの例では、オブジェクトx={id: 1, name: "ha"}
、y={id: 1, name: "foo"}
は、z={id: 2, name: "bar"}
この特性を有する(x.equals(y) and y.equals(z))
。しかし、false
f(x)==f(y)
です。すべてのx==y
方法は、Java APIのドキュメントを参照して、このプロパティを持っている必要があります。
バック機能をハッシュする:すべての機能が<=>によって定義された等価性を生み出します。あなたは、関数値の比較に興味があり、それが<=>場合はtrueを返します(そしておそらく他の例では)したい場合には意味、あなたは、少なくとも推移閉包を考慮しなければならないことを意味推移の関係を、受け取りますオブジェクトの同値。あなたのケースでは、推移閉包は些細な関係(すべては何にも等しい)です。これはあなたが任意の関数によって異なるオブジェクトを区別できないことを意味します。
あなたは意図的平等を定義していますか?
あなたは、あなたのハッシュコードを使用して計算する必要がある意味「AND」場合)あなたが(等号であるフィールド。非常に同じかそれ以下(ただし、等号で使用されていないフィールドを使用することはありません)。
あなたは、あなたがhashgcodeは理にかなって本当にdoesntのそのハッシュコードの計算にIDまたは名前を含めるべきではありませんrの意味「OR」場合ます。
編集:私は慎重に質問を読んでいない
。-
私はコモンズ-LANGの瓶を使用します。
XORメンバーのhashCodeべき作品。彼らは正しくのhashCode()とequals()を実装しなければならないとしてます。
しかし、あなたのコードが間違っているあなたは、あなたのハッシュコードを保護しないことがあります。 それはハッシュ化された後は、変更しないでください。それが起こるのを防止する必要があります。
public hashCode(){
return new AssertionError();
}
または
public class MyClass {
final int id;
final String name;
// constructor
}
または
public class MyClass {
private int id;
private String name;
boolean hashed=false;
public void setId(int value){
if(hashed)throw new IllegalStateException();
this.id=value;
}
public void setName(String value){
if(hashed)throw new IllegalStateException();
this.name=value;
}
// your equals() here
public hashCode(){
hashed=true;
return new HashCodeBuilder().append(id).append(name).toHashCode();
}
}
質問を再読み込みした後ます。
あなたはそれらのいずれかが更新されている別のフィールドを自動的に完了することがあります。
-
編集:私のコードは私の英語、その後、より良いと言うことがあります。
。void setName(String value){
this.id=Lookup.IDbyName(value);
}
void setID(String value){
this.name=Lookup.NamebyId(value);
}
EDIT 2:
あなたは、ID&名の両方を設定していない限り、問題のコードが間違っていると常にtrueを返しますがあります。
あなたが本当に一部の等号を行う方法をしたい場合は、、あなたの名前の独自のAPI作成「partialEqualsを()」。
最も単純な経路は、個々のフィールドのハッシュコードをXORすることです。これは、いくつかの状況ではマイナーな醜(例えばX、Y座標で、それはあなたがXとYを反転するとき同じハッシュを持つことの潜在的に貧しい状況の原因となる)が、全体的にかなり効果的であるがあります。必要に応じて、効率のために衝突を軽減するために、必要に応じて微調整します。
これはどのように
public override int GetHashCode()
{
return (id.ToString() + name.ToString()).GetHashCode();
}
関数はオールウェイズ「有効」のハッシュを返す必要があります...
編集:ちょうどあなたが使用していることに気づいた「か」ない「と」:... Pも私はこの問題への良い解決策がある疑い。
どの程度
public override int GetHashCode()
{
return id.GetHashCode() ^ name.GetHashCode();
}