ハッシュセットの私の疑問を明確にしてください。次のコードを検討してください。
_class Person
{
String name;
Person(String n)
{
name=n;
}
public String getName()
{
return name;
}
@Override
public boolean equals(Object arg0) {
System.out.println("in equals");
Person obj=(Person)arg0;
System.out.println("1st "+getName());
System.out.println("2nd "+obj.getName());
if(this.getName().equals(obj.getName()))
{
return true;
}
return false;
}
@Override
public int hashCode() {
System.out.println("in hash code");
System.out.println(" value is "+Integer.valueOf(name.charAt(0)));
return Integer.valueOf(name.charAt(0));
}
}
_
主に私は次のコードを持っています
_Person obj1=new Person("bcd");
Person obj2=new Person("cde");
Person obj3=new Person("abc");
Person obj4=new Person("abc");
_
これらのオブジェクトをハッシュセットに追加すると
_Set<Person> sset=new HashSet<Person>();
sset.add(obj1);
sset.add(obj4);
sset.add(obj2);
sset.add(obj3);
_
この出力を取得しています
_in hash code
value is 98
in hash code
value is 97
in hash code
value is 99
in hash code
value is 97
in equals
1st abc
2nd abc
_
質問1:obj3とobj4をチェックするために、equals()関数が一度だけ呼び出されるのはなぜですか?残りのオブジェクトをチェックしないのはなぜですか?
質問2:両方が同じハッシュコードを持っているためである場合、等しい場合のみが呼び出され、次に以下のコードでは呼び出されない理由
_sset.add(obj1);
sset.add(obj4);
sset.add(obj2);
sset.add(obj4);
_
出力は次のとおりです。
_in hash code
value is 98
in hash code
value is 97
in hash code
value is 99
in hash code
value is 97
_
同じハッシュコードを持つハッシュセットに2つの同じオブジェクトが追加されていても、equals()メソッドの内部には行きません。
質問:上記の値を繰り返して内容を出力しましたが、ハッシュコードもイコールも呼び出されませんでした。 hashcode and equalsメソッドをオーバーライドすることが本当に便利なときは?
質問4:hashCode()
およびequals()
はいつ呼び出されますか?
equals
が異なる場合、hashCode
を呼び出す必要はありません。(obj1 == obj2)
の場合、hashCode
を呼び出す必要はありません。hashCode
やequals
は必要ありません-オブジェクトを比較するわけではありませんセット、特にHashSetがどのように機能するかを理解すれば、あなたの質問はすべて答えられると思います。セットは一意のオブジェクトのコレクションであり、Javaは一意性を定義し、それは他とは等しくない(equalsはfalseを返します)。
HashSetはハッシュコードを利用して速度を上げます。互いに等しい2つのオブジェクトが同じハッシュコードを持つと仮定します。ただし、同じハッシュコードを持つ2つのオブジェクトが等しいことを想定していません。これが、衝突するハッシュコードを検出すると、同じハッシュコードを持つセット内の他のオブジェクト(あなたの場合は1つ)とのみ比較する理由です。
javasourcecode.orgのjdkソースコードによると、HashSetは内部実装としてHashMapを使用します。HashSetのputメソッドに関するコードは以下のとおりです。
public V put(K key, V value) {
if (key == null)
return putForNullKey(value);
int hash = hash(key.hashCode());
int i = indexFor(hash, table.length);
for (Entry<K,V> e = table[i]; e != null; e = e.next) {
Object k;
if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {
V oldValue = e.value;
e.value = value;
e.recordAccess(this);
return oldValue;
}
}
modCount++;
addEntry(hash, key, value, i);
return null;
}
ルールは最初にハッシュをチェックし、次に参照をチェックしてから、オブジェクトのequalsメソッドを呼び出します
2番目の場合、同じ参照を2回追加し、HashSet
はHashSet
の基になっているHashMap.put()
でこれをチェックするため、
if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {
V oldValue = e.value;
e.value = value;
e.recordAccess(this);
return oldValue;
}
ご覧のとおり、equals
は、追加されるキーのハッシュがセットに既に存在するキーと等しい場合にのみ呼び出されますおよびこれら2つの参照は異なります。
EqualsとhashCodeを適切に実装したことを確認する方法を読んでください。これは良い出発点です: JavaでequalsとhashCodeをオーバーライドするときに考慮すべき問題は何ですか?