2013-01-21 27 views
21

如果在HotSpot Java 7 64位版本上運行以下操作。是否有理由Object.hashCode()是31位?

int countTopBit = 0, countLowestBit = 0; 
for (int i = 0; i < 100000000; i++) { 
    int h = new Object().hashCode(); 
    if (h < 0) 
     countTopBit++; 
    if ((h & 1) == 1) 
     countLowestBit++; 
} 
System.out.println("The count of negative hashCodes was " + countTopBit + ", the count of odd hashCodes was " + countLowestBit); 

你可以像

The count of negative hashCodes was 0, the count of odd hashCodes was 49994232 

結果我在想,如果這意味着Object.hashCode()是唯一真正31位和爲什麼會是這樣?


不是最高位未被使用的情況。從源HashMap中

257 /** 
258 * Applies a supplemental hash function to a given hashCode, which 
259 * defends against poor quality hash functions. This is critical 
260 * because HashMap uses power-of-two length hash tables, that 
261 * otherwise encounter collisions for hashCodes that do not differ 
262 * in lower bits. Note: Null keys always map to hash 0, thus index 0. 
263 */ 
264 static int hash(int h) { 
265  // This function ensures that hashCodes that differ only by 
266  // constant multiples at each bit position have a bounded 
267  // number of collisions (approximately 8 at default load factor). 
268  h ^= (h >>> 20)^(h >>> 12); 
269  return h^(h >>> 7)^(h >>> 4); 
270 } 
+0

這可能是一個優化。哈希表通常將哈希碼mod作爲桶的數量,但必須首先屏蔽掉最高位以避免負索引。也許這是爲了避免後面的那一步? – templatetypedef

+0

@templatetypedef我確實懷疑這可能是這種情況,但我懷疑Object.hashCode()並沒有在哈希集合中使用,因爲它通常被32位hashCode()重寫。此外,HashMap會對原始hashCode進行變異,以便使用最高位。 –

+2

@templatetypedef:但是用戶替代不會這樣做? Hash表仍然需要處理 –

回答

13

熱點支持各種哈希算法爲Object的。正如您所emprically發現,頂部位總是屏蔽掉返回結果前:

// src/share/vm/runtime/synchronizer.cpp 
static inline intptr_t get_next_hash(Thread * Self, oop obj) { 
    ... 
    value &= markOopDesc::hash_mask; 
    ... 
    return value; 
} 

markOopDesc::hash_mask計算如下:

enum { age_bits     = 4, 
     lock_bits    = 2, 
     biased_lock_bits   = 1, 
     max_hash_bits   = BitsPerWord - age_bits - lock_bits - biased_lock_bits, 
     hash_bits    = max_hash_bits > 31 ? 31 : max_hash_bits, 
     ... 
     hash_mask    = right_n_bits(hash_bits), 

正如你所看到的,markOopDesc::hash_mask總是有位31設置爲零。

至於爲什麼這樣做,你的猜測和我一樣好。原本的開發者可能認爲只有處理正整數才能簡化事情。對於我們所知道的,它甚至可能是hash_bits計算中的一個錯誤。 ;-)

+0

+1隨着SWeko發現,C#做了同樣的事情,這表明可能有一個共同的原因。或者可能是他們複製了一個通用的實現,這是由於不再適用的原因。 –

+0

'right_n_bits'不可能正確地將32作爲參數。我正在構建Java 8,所以我有一個源代碼的副本可供參考。 ;) –

相關問題