为什么在添加HashSet和hashCode匹配时没有调用equals()? [英] Why is equals() not called while adding to HashSet and hashCode matches?
问题描述
当我运行此代码时,为什么只有 hashCode()
被调用而不是等于
方法,而我的 hashCode()
实现为 HashSet
的两个条目生成相同的 hashCode
?
When I run this code why only hashCode()
is called not equals
method while my hashCode()
implementation generate same hashCode
for both entries to HashSet
?
import java.util.HashSet;
public class Test1 {
public static void main(String[] args) {
Student st=new Student(89);
HashSet st1=new HashSet();
st1.add(st);
st1.add(st);
System.out.println("Ho size="+st1.size());
}
}
class Student{
private int name;
private int ID;
public Student(int iD) {
super();
this.ID = iD;
}
@Override
public int hashCode() {
System.out.println("Hello-hashcode");
return ID;
}
@Override
public boolean equals(Object obj) {
System.out.println("Hello-equals");
if(obj instanceof Student){
if(this.ID==((Student)obj).ID){
return true;
}
else{
return false;
}
}
return false;
}
}
此输出为:
Hello-hashcode
Hello-hashcode
Ho size=1
推荐答案
哈希集首先检查引用相等性,如果超过,则跳过 .equals
致电。这是一个优化并且有效,因为的合约等于
指定如果 a == b
那么 a.equals(b)中
。
The hash set checks reference equality first, and if that passes, it skips the .equals
call. This is an optimization and works because the contract of equals
specifies that if a == b
then a.equals(b)
.
我附上了下面的源代码,突出显示了这个检查。
I attached the source code below, with this check highlighted.
如果你改为添加两个相等的元素不是相同的参考,你得到你期望的效果:
If you instead add two equal elements that are not the same reference, you get the effect you were expecting:
HashSet st1=new HashSet();
st1.add(new Student(89));
st1.add(new Student(89));
System.out.println("Ho size="+st1.size());
结果
$ java Test1
Hello-hashcode
Hello-hashcode
Hello-equals
Ho size=1
这是来自OpenJDK 7的源代码,指示了相等优化(来自HashMap,HashSet的底层实现):
Here's the source code from OpenJDK 7, with equality optimization indicated (from HashMap, the underlying implementation of HashSet):
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;
// v-- HERE
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;
}
这篇关于为什么在添加HashSet和hashCode匹配时没有调用equals()?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!