道歉的相當天真的問題,但我相信我自己的答案是天真的。我認爲密鑰(在HashTables中)是不可變的,因爲我們不想以某種方式意外地改變密鑰,因此混亂了HashTable的排序。這是一個正確的解釋嗎?如果是這樣,它怎麼會更正確?爲什麼鍵在Java中是不可變的?
回答
在HashTable.put
密鑰被散列,並將其一個其值被存儲在一個數段(其是關鍵值對列表)根據散列中的一個,例如是這樣的:
bucket[key.hashcode() % numberOfBuckets].add(key, value)
如果鑰匙的插入後hashcode
改變它才能再在錯誤的桶,你會再無法找到它,並在哈希表會錯誤地在任何get
返回null
該鍵。
旁白:瞭解一個哈希表的內部工作原理可以幫助你瞭解你的鑰匙優質hashcode
功能的重要性。由於糟糕的哈希碼功能可能導致密鑰在桶中分佈不良。由於存儲桶只是列表,導致大量的線性搜索,大大降低了哈希表的有效性。例如這個可怕的hashcode函數將所有內容放在一個桶中,所以它實際上只是一個列表。
public int hashcode { return 42; /*terrible hashcode example, don't use!*/ }
這也是原因之一質數出現在良好的哈希碼的功能,例如:
public int hashcode {
int hash = field1.hashcode();
hash = hash*31 + field2.hashcode(); //note the prime 31
hash = hash*31 + field3.hashcode();
return hash;
}
的總體思路是正確的,但不是它的細節。
鍵在哈希表中不一定是一成不變的,這是他們的hashCode()
(和equals
)方法調用,需要留不變和的結果是一致的(用於哈希表的行爲不難看出,那是) 。
從一個高層次的點,這是因爲單向散列表工作:當插入(key
,value
)對,key
的的hashCode用於內部找出一個‘桶’,其中價值將被放置。當被key
檢索時,hashCode
被再次計算,以找回存儲桶。
現在,如果在插入和retreival之間的任何時間點,稱hashCode
變化的結果,在「查找鬥」會比「插入」鬥不同,事情不會表現預見的。
綜上所述,給予重點對象,看起來像這樣(兩個內部串組成的客體,但只有一個,partOfHashCode
被考慮到的hashCode /等於):
public static class Key {
private String partOfHashCode;
private String notPartOfHashCode;
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((partOfHashCode == null) ? 0 : partOfHashCode.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Key other = (Key) obj;
if (partOfHashCode == null) {
if (other.partOfHashCode != null)
return false;
} else if (!partOfHashCode.equals(other.partOfHashCode))
return false;
return true;
}
}
的很精緻以這種方式使用它:
public static void main(String[] args) {
Map<Key, String> myMap = new HashMap<>();
Key key = new Key();
key.partOfHashCode = "myHash";
myMap.put(key, "value");
key.notPartOfHashCode = "mutation of the key, but not of its hash/equals definition";
System.out.println(myMap.get(key));
}
(這會在控制檯中記錄「value」對象)。
但它不是蠻好用的這種方式
public static void main(String[] args) {
Map<Key, String> myMap = new HashMap<>();
Key key = new Key();
key.partOfHashCode = "myHash";
myMap.put(key, "value");
key.partOfHashCode = "mutation of the hashCode of the key";
System.out.println(myMap.get(key));
}
(最後這個例子可以登錄控制檯「空」)。
有關此主題的更多信息,還應閱讀hashCode/equals一致性。
在Java中沒有固有的保證,即鍵不可變。它甚至不保證它們的hashcode
保持不變。但是如果你添加了一個可變的鑰匙,你就有麻煩了。假設您插入的密鑰的hashCode
爲1.然後將其插入到對應於1的哈希桶中。然後更改該對象使其具有hashCode
爲2並呼叫hashMap.get(key)
。雖然對象仍在hashTable
中,但系統將在對應於2的存儲區中查找,但不會在此處找到它。因爲它不會被發現,所以你甚至無法登錄remove
。
tl; dr爲使您的應用程序正常工作HashTable
-鍵需要有固定的hashcode
s,但您必須自己處理這一事實。
- 1. 爲什麼String對象在java中是不可變的?
- 2. 爲什麼java中的字符串是不可變的?
- 3. 在Java中,爲什麼instanceof是關鍵字而不是方法?
- 4. 爲什麼JavaScript NodeList是不可變的?
- 5. 爲什麼可以在PHP中重寫實例變量而不是在Java中?
- 6. scala.collection.mutable中的HashMap是不變的,但不可變.HashMap是協變的,爲什麼?
- 7. 我不明白爲什麼在Java中不可變對象inherrently總是線程
- 8. 爲什麼在Python中`object`類的實例是不可變的?
- 9. 爲什麼要在Java中聲明一個不可變類final?
- 10. 爲什麼數字在Javascript中是不可變的?
- 11. 爲什麼整數在Python中是不可變的?
- 12. 什麼是可以使外鍵變爲不可信的一些場景
- 13. 除了Java中的String之外,什麼是不可變對象?
- 14. 在java中可比較的是什麼?
- 15. 爲什麼Java中的類默認是不可複製的
- 16. Java中的native關鍵字是什麼?
- 17. 什麼是Java中的關鍵字?
- 18. 在Rust中,究竟是什麼是可變的和不可變的借入?
- 19. 在Express中,爲什麼.config()中的env變量是可選的?
- 20. 爲什麼.NET異常是可變的?
- 21. 爲什麼塊變量是可選的?
- 22. 爲什麼在java中有變量
- 23. 爲什麼變量n在Java中的第二個偵聽器中不可見?
- 24. java中爲什麼不是(123 == 0123)?
- 25. 爲什麼鍵入我的變量對象,而不是數字
- 26. 爲什麼我的redux商店不是不可變的?
- 27. 爲什麼可變和不可變ListMaps在Scala中有不同的順序?
- 28. 什麼是可能的循環不變
- 29. 爲什麼接口變量在Java中是隱式靜態的?
- 30. 這是爲什麼可能在Java中:this.getClass()的getClass()的getClass()......等