![](/img/trans.png)
[英]HashSet.contains does not behave as expected with hashCode and equals
[英]Number of calls of hashCode() and equals() in case of HashSet.contains() if hashcode returns a constant value
我已閱讀過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()
在這種情況下只調用hashCode()
)? object3
情況下調用equals()
兩次? 當您向Set
添加元素時,它將存儲在Map
內部,其中key是您傳入的對象,value設置為null
。 內部Map
維護鏈表的數組(存儲桶)。 這些陣列也可稱為存儲桶。 使用hashCode()
方法評估存儲桶的索引。
在您的情況下,因為hashCode()返回一個常量值,所以放入Set的所有值都將放在同一個桶中。 所以對於第一次調用set.add(object1)
內部結構就是這樣的
bucket [object1 - > null]
由於每個存儲桶包含一個鏈表,因此存儲在列表中的元素具有指向下一個元素的指針。 由於只有一個元素添加到列表中,因此指針指向null
。
對於下一次調用set.add(object2)
數據結構將如下所示
bucket [object2 - > object1 - > null]
現在每當你調用set.contains(some_object)
,都會調用hashCode()
來找出正確的存儲桶。 此調用還返回對第一個元素的引用。
回答第一個問題:
因此,當您調用set.contains(object2)
它實際上返回對object2
引用。 現在,如果查看HashMap
類的代碼,它首先使用==
運算符比較此引用是否與傳入的引用相同。 因為在這種情況下它是相同的所以它不會調用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
,因此它遍歷list並返回對列表中下一個元素的引用,即object1
。
同樣, object1 == object3
返回false,因此Map調用object3.equals(object1)
(第二次調用equals()
方法)方法來檢查兩個對象是否有意義相等。
這導致2次調用equals()
方法。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.