2009-06-30 47 views
62

通常默認實現Object.hashCode()是對象在內存中分配地址的某些功能(雖然這不是由JLS強制執行的)。鑑於虛擬機在內存中分流對象,爲什麼在對象的生命週期中,返回的值爲什麼不會改變?如果是「一次性」計算(對象的hashCode計算一次並隱藏在對象頭部或某物中),那麼這是否意味着兩個對象可能具有相同的identityHashCode(如果它們發生的話)首先分配在內存中的相同地址)?JVM如何確保System.identityHashCode()永遠不會改變?

+1

相關問題:這個內存地址是一個真實的內存地址還是虛擬的東西,即使對象被混洗也可以保持固定?如果是虛擬的,那會很好,因爲指向它的指針不需要調整。另一方面,這意味着一個額外的間接和一個潛在的大映射表。 – Thilo 2009-06-30 11:06:04

+3

這是第一次要求時地址的輕微重新排列。 (用低位返回一個散列碼全零不是很好) – 2009-06-30 11:14:05

+0

實際上,它在哪裏說identityHashCode一定不會改變?對於System.identityHashCode的JavaDoc並不清楚。 – Thilo 2009-06-30 11:32:57

回答

35

現代JVM將值保存在對象頭中。我相信這個值通常只在第一次使用時計算,以便將花費在對象分配上的時間降到最低(有時甚至低至十幾個週期)。通用Sun JVM可以被編譯,以便所有對象的身份哈希碼始終爲1。

多個對象可以具有相同的標識哈希碼。這是散列碼的本質。

-3

據我所知,這是實現返回引用,這將永遠不會改變對象的生命週期。

15

在回答第二個問題時,不管實現如何,多個對象可能具有相同的identityHashCode。

請參閱bug 6321873關於javadoc中的措辭的簡要討論以及演示非唯一性的程序。

0

用於實現散列函數的一般原則是:

  • 同一個對象應返回一致的hashCode,它不應該隨時間而變化或依賴於任何可變信息(例如,由種子的算法隨機數字或值的可變成員字段
  • 散列函數應該有一個良好的隨機分佈,我的意思是如果你認爲哈希碼作爲桶,2個對象應儘可能映射到不同的桶(哈希碼) 。2個對象的可能性將有相同的哈希碼應該是罕見的 - 雖然它可以發生。
0

HotSpot中對象的標題由類指針和「標記」字組成。

標記字的數據結構的源代碼可以在markOop.hpp文件中找到。在該文件的標記字的註釋,描述內存佈局:

hash:25 ------------>| age:4 biased_lock:1 lock:2 (normal object)

在這裏我們可以看到,對於普通的Java的身份哈希碼在32位系統上的對象保存在標記詞,它是25位長。