2009-12-10 37 views
7

我有一個應用程序顯示行中的對象集合,一個對象=一行。這些對象存儲在一個HashMap中。行的順序不會影響應用程序的功能(這就是爲什麼使用HashMap而不是可排序的集合)。當在JVM5 vs JVM6中運行相同的程序時,HashMap中的項目順序有所不同

但是我注意到,使用兩個不同版本的Java虛擬機運行時,同一應用程序的運行方式不同。該應用程序使用JDK 5進行編譯,可以使用Java 5或Java 6運行時運行,沒有任何功能差異。

有問題的對象會覆蓋java.lang.Object#hashCode(),並且顯然已經注意遵循Java API中指定的協議。事實證明這一點,即在應用程序的每次運行中(在同一個Java運行時),它們總是以相同的順序出現。

爲了好奇,爲什麼選擇Java運行時會影響順序?

+2

('LinkedHashMap'可以給你一致的順序。) –

回答

17

HashMap的實施細則可以做改變。很可能這包私有方法做(這是JDK 1.6.0_16):

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

作爲參考,在JDK 1.5.0_06類似物是:

/** 
* Returns a hash value for the specified object. In addition to 
* the object's own hashCode, this method applies a "supplemental 
* hash function," which defends against poor quality hash functions. 
* This is critical because HashMap uses power-of two length 
* hash tables.<p> 
* 
* The shift distances in this function were chosen as the result 
* of an automated search over the entire four-dimensional search space. 
*/ 
static int hash(Object x) { 
    int h = x.hashCode(); 

    h += ~(h << 9); 
    h ^= (h >>> 14); 
    h += (h << 4); 
    h ^= (h >>> 10); 
    return h; 
} 
+2

+1;邁克爾,我已經添加了來自JDK 5的等效代碼來說明這一點;如果你覺得它不適合你的答案,請恢復我的編輯。 –

+0

+1 ....我可以給Andrzej一票嗎? :) – skaffman

+0

不,這正是我懶得挖掘,沒有1.5 JDK手頭。 –

10

可能因爲Map沒有被定義爲具有任何特定的迭代次序;元素返回的順序很可能是其內部實現的人工產物,並且不需要保持一致。

如果實現在Java 5和Java 6之間更新(特別是出於性能原因),Sun沒有任何好處或義務確保迭代順序在兩者之間保持一致。

編輯:我剛剛發現了一個有趣的片段在早期的Java 6版本之一(可惜我不知道確切的版本,但它從六月份的明顯的HashMap 1.68 2006):

/** 
    * Whether to prefer the old supplemental hash function, for 
    * compatibility with broken applications that rely on the 
    * internal hashing order. 
    * 
    * Set to true only by hotspot when invoked via 
    * -XX:+UseNewHashFunction or -XX:+AggressiveOpts 
    */ 
private static final boolean useNewHash; 
static { useNewHash = false; } 

private static int oldHash(int h) { 
    h += ~(h << 9); 
    h ^= (h >>> 14); 
    h += (h << 4); 
    h ^= (h >>> 10); 
    return h; 
} 

private static int newHash(int h) { 
    // This function ensures that hashCodes that differ only by 
    // constant multiples at each bit position have a bounded 
    // number of collisions (approximately 8 at default load factor). 
    h ^= (h >>> 20)^(h >>> 12); 
    return h^(h >>> 7)^(h >>> 4); 
} 

因此,儘管我有上述斷言,但事實上,Sun確實考慮了迭代次序的一致性 - 在稍後的時間點,這段代碼可能會被刪除,而新的次序會作出明確的決定。

+0

是的,我知道。如果訂單對我來說很重要,我會選擇保存訂單的另一種類型的集合。我只是好奇爲什麼。 +1編輯爲@Michael Borgwardt的回答 – bguiz

0

HashMap中沒有結婚任何特定排序,但LinkedHashMap執行Map應該保留順序。

相關問題