我已阅读过Java文档页面,但我无法解释为什么hashCode()
和equals()
的来电次数会有这样的变化?
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
public class NumberOfCalls {
int field;
public int getField() {
return field;
}
public NumberOfCalls(int field) {
this.field = field;
}
@Override
public int hashCode() {
System.out.println("In Hashcode method.");
return 10;
}
@Override
public boolean equals(Object obj) {
System.out.println("In Equals Method");
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
NumberOfCalls other = (NumberOfCalls) obj;
if (field != other.field)
return false;
return true;
}
public static void main(String[] args) {
NumberOfCalls object1 = new NumberOfCalls(5);
NumberOfCalls object2 = new NumberOfCalls(6);
NumberOfCalls object3 = new NumberOfCalls(5);
Set<NumberOfCalls> set = new HashSet<NumberOfCalls>();
set.add(object1);
set.add(object2);
Iterator<NumberOfCalls> it = set.iterator();
System.out.print("Size of set is : " + set.size()
+ "\nObject fields values present in set are : ");
while (it.hasNext()) {
System.out.print(it.next().getField() + " ");
}
System.out.println("\n---------------------------------------------------");
System.out.println("Now checking number of calls -- ");
System.out.println("Object1 is present in set ? - " + set.contains(object1)+"\n");
System.out.println("Object2 is present in set ? - " + set.contains(object2)+"\n");
System.out.println("Object3 is present in set ? - " + set.contains(object3)+"\n");
}
}
上述代码的输出为
在Hashcode方法中。
在Hashcode方法中。
在等于方法中 套装尺寸为:2
集合中存在的对象字段值为:6 5
----------------------------------------------- ----
现在检查通话次数 -
在Hashcode方法中。
在等于方法中 对象1出现在集合中? - 的真实
在Hashcode方法中。
对象2出现在集合中? - 的真实
在Hashcode方法中。
在等于方法中 在等于方法中 对象3出现在集合中? - 的真实
问题:
hashCode()
和equals()
在object1
而非object2
(在这种情况下仅调用hashCode()
)时,为什么会一次调用?{ / LI>
equals()
object3
两次
醇>
答案 0 :(得分:7)
当您向Set
添加元素时,它会存储在Map
内部,其中key是您传入的对象,value设置为null
。内部Map
维护链表的数组(存储桶)。这些阵列也可称为存储桶。使用hashCode()
方法评估存储桶的索引。
在你的情况下,因为hashCode()返回一个常量值,所以放入Set的所有值都将放在同一个桶中。因此,对于第一次调用set.add(object1)
,内部结构将类似于
bucket [object1 - &gt;空]
由于每个存储桶都包含一个链表,因此存储在列表中的元素具有指向下一个元素的指针。由于只有一个元素添加到列表中,因此指针指向null
。
对于下一个电话set.add(object2)
,数据结构将如下所示
bucket [object2 - &gt; object1 - &gt;空]
现在,只要您拨打set.contains(some_object)
,就会调用hashCode()
来找出正确的存储桶。此调用还返回对第一个元素的引用。
回答第一个问题:
因此,当您致电set.contains(object2)
时,它实际上会返回对object2
的引用。现在,如果你看一下HashMap
班级&#39;代码首先使用==
运算符比较此引用是否与传入的引用相同。因为在这种情况下它是相同的,所以它不会调用equals()
方法。以下是HashMap
类的代码段:
if (e.hash == hash &&
((k = e.key) == key || (key != null && key.equals(k))))
return e;
这应该解释你的第一个问题。
回答第二个问题:
当您致电set.contains(object3)
时,会计算存储桶索引并返回对object2
的引用。现在object2 == object3
返回false,因此Map调用object3.equals(object2)
方法(首次调用equals()
方法)来检查两个对象是否有意义相等。这也返回false
,因此它遍历列表并返回对列表中下一个元素的引用,即object1
。
再次object1 == object3
返回false,因此Map调用object3.equals(object1)
(第二次调用equals()
方法)方法来检查两个对象是否有意义等效。
这会导致2次调用equals()
方法。