HashSet類有一個add(Object o)方法,它不會從另一個類繼承。該方法的Javadoc說明如下:爲什麼HashSet允許相同的項目,如果hashcodes是不同的?
如果指定的元素不存在,則將該元素添加到此集合中。更正式地說,如果該集合不包含
e2
這樣的(e==null ? e2==null : e.equals(e2))
,則將指定元素e
添加到該集合。如果該集合已包含該元素,則該呼叫將保持該集合不變並返回false
。
換句話說,如果兩個對象相等,那麼第二個對象將不會被添加,並且HashSet將保持不變。但是,我發現如果對象e
和e2
具有不同的哈希碼,則不是這樣,儘管事實上是e.equals(e2)
。下面是一個簡單的例子:
import java.util.HashSet;
import java.util.Iterator;
import java.util.Random;
public class BadHashCodeClass {
/**
* A hashcode that will randomly return an integer, so it is unlikely to be the same
*/
@Override
public int hashCode(){
return new Random().nextInt();
}
/**
* An equal method that will always return true
*/
@Override
public boolean equals(Object o){
return true;
}
public static void main(String... args){
HashSet<BadHashCodeClass> hashSet = new HashSet<>();
BadHashCodeClass instance = new BadHashCodeClass();
System.out.println("Instance was added: " + hashSet.add(instance));
System.out.println("Instance was added: " + hashSet.add(instance));
System.out.println("Elements in hashSet: " + hashSet.size());
Iterator<BadHashCodeClass> iterator = hashSet.iterator();
BadHashCodeClass e = iterator.next();
BadHashCodeClass e2 = iterator.next();
System.out.println("Element contains e and e2 such that (e==null ? e2==null : e.equals(e2)): " + (e==null ? e2==null : e.equals(e2)));
}
從主方法的結果是:
Instance was added: true
Instance was added: true
Elements in hashSet: 2
Element contains e and e2 such that (e==null ? e2==null : e.equals(e2)): true
如上面的例子中清楚地示出,HashSet的是能夠添加兩個元素,其中e.equals(e2)
。
我打算假設這是而不是 Java中的一個錯誤,並且事實上存在一些完全合理的解釋。但我無法弄清楚究竟是什麼。我錯過了什麼?
不要聽瘋子的咆哮;無論發生在這種情況下,只是一個破碎系統的尖叫。您只應該擔心糾正程序中的哈希集問題 –
無論您在此處觀察到什麼行爲都可以隨時更改而沒有任何警告,因爲它是對違反合同的響應,因此它是未記錄的,並且未來版本的Java沒有義務維護行爲。依靠這種行爲將是一個嚴重的錯誤 –
「有兩次我被問到,'請問巴貝奇先生,如果你把錯誤的數字放進機器,會得出正確的答案嗎? ......我無法正確理解可能引發這樣一個問題的那種混淆思想。「 〜Charles Babbage – dimo414