簡體   English   中英

內存地址作為哈希表中的哈希。 HasTable為什么不能將Key的實際內存地址用作Hash?

[英]Memory Address as Hash in HashTable. Why can't HasTable use actual memory address of the Key as Hash?

可能這是一個基本問題或背后的基本思想。

HasTable為什么不能將Key的實際內存地址用作Hash? 或哈希密鑰的地址並使用它?

我看到一些帖子說鍵(對象)的默認hashCode()實際上是對象的內存地址,我認為這是不正確的。

我在帖子中讀到,存儲區地址實際上hash % number of existing buckets 這也不正確。

有人可以澄清嗎?

如果一個類不重寫hashCode() ,而只是從java.lang.Object繼承默認實現,那么在典型的JVM中,其hashCode()實際上或多或少是指向它的內部指針。 (顯然,這不是全部,因為hashCode()的返回類型是int ,它不能容納64位JVM;而且這些也不是指向物理內存位置的真正指針,首先是因為OS處理了來自虛擬地址到物理地址,其次,因為即使JVM處理了,垃圾回收器也可以將對象從一個堆移到另一個堆,而不會影響其hashCode() ,但是“內部內存地址”仍然是一個很好的第一近似值。 )

大多數JDK類重寫hashCode()是,我們始終希望hashCode()equals() “兼容”; 也就是說,如果a.equals(b) ,那么我們需要a.hashCode() == b.hashCode() (這在您認為您通常不希望(例如,一個Map<String, Object>僅僅具有兩個不同的String實例的鍵)具有兩個不同的"abc"條目時才有意義。通常,您希望能夠通過鍵入map.get("abc")來查找條目,而不需要map.get("abc")獲取鍵的原始實例。如果兩個鍵相等,那么我們通常希望將它們視為相等。)

如果您確實想在地圖中使用指針相等,則可以使用java.util.IdentityHashMap

默認的Object.hashCode()嚴格來說不是內存地址,但是除非您有巨大的內存,否則它在JVM中的所有對象中確實是唯一的,因此您可以將其視為“邏輯”地址。

HashMap具有有限數量的存儲桶,每個鍵的確根據其哈希碼分配了存儲桶。 每個哈希碼沒有一個存儲桶。 因此,即使兩個對象具有不同的哈希碼,它們也可能以相同的桶結尾。 這就是為什么必須盡可能合理地分布hashCode以避免這種沖突的原因。

在大多數情況下,不希望使用鍵的系統標識哈希碼(即Object.hashCode()返回的哈希碼Object.hashCode() ,因為如果兩個鍵具有相同的信息,而不是兩個鍵,則希望它們相等。同一對象實例。 例如,如果您將一個學生存儲在基於他的SSN的地圖中,然后從某個Web服務或數據庫中獲取該學生的SSN,則您將沒有相同的STring實例,但是您希望能夠使用收到的SSN在地圖上找到學生。

為什么HashTable不能將Key的實際內存地址用作Hash?

因為關鍵平等很重要。 當兩個對象“相等”時( one.equals(two)返回true),哈希碼也必須相等( one.hashCode() == two.hashCode() )。

默認的hashCode() 不是內存地址,而是“身份哈希”。

內存地址可能會更改,但是身份對於給定實例是恆定的。

您可以擁有自己認為是最佳的hashCode的任何實現,而無需違反為hashCode設置的規則並在JavaSE api中等於它。

在此處檢查等於和哈希碼規則: http : //docs.oracle.com/javase/6/docs/api/java/lang/Object.html

這很重要,因為Collections庫和其他api嚴重依賴此屬性來實現自己的行為。

內存地址不應用作對象的hashCode(除非其equals方法僅執行身份比較)。 原因明確地寫在其JavaDoc中

如果根據{@code equals(Object)}方法兩個對象相等,則在兩個對象中的每個對象上調用{@code hashCode}方法必須產生相同的整數結果。

在equals方法僅執行一個身份比較的情況下,內存地址就足夠了,因為hashCode()和equals()都只對同一個對象相等。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM