2009-04-13 137 views
39

這很奇怪。一位同事詢問了java中myArray.hashCode()的實現。我以爲我知道,但後來我跑了一些測試。檢查下面的代碼。我注意到奇怪的是,當我寫出第一個系統時,結果是不同的。請注意,它幾乎就像報告內存地址並修改類地址或其他內容一樣。只是想我會分享。Java Array HashCode實現

int[] foo = new int[100000]; 
java.util.Random rand = new java.util.Random(); 

for(int a = 0; a < foo.length; a++) foo[a] = rand.nextInt(); 

int[] bar = new int[100000]; 
int[] baz = new int[100000]; 
int[] bax = new int[100000]; 
for(int a = 0; a < foo.length; a++) bar[a] = baz[a] = bax[a] = foo[a]; 

System.out.println(foo.hashCode() + " ----- " + bar.hashCode() + " ----- " + baz.hashCode() + " ----- " + bax.hashCode()); 

// returns 4097744 ----- 328041 ----- 2083945 ----- 2438296 
// Consistently unless you modify the class. Very weird 
// Before adding the comments below it returned this: 
// 4177328 ----- 4097744 ----- 328041 ----- 2083945 


System.out.println("Equal ?? " + 
    (java.util.Arrays.equals(foo, bar) && java.util.Arrays.equals(bar, baz) && 
    java.util.Arrays.equals(baz, bax) && java.util.Arrays.equals(foo, bax))); 

回答

77

java.lang.Array的方法hashCodeObject,這意味着散列碼取決於參考繼承。要獲取基於數組內容的哈希碼,請使用Arrays.hashCode

要小心,儘管它的淺碼哈希碼實現。深入實施還存在Arrays.deepHashCode

+1

感謝這個答案,但爲什麼java.lang.Array默認不重寫hashCode(和toString)方法?有沒有什麼好的理由? – 2013-05-07 21:05:24

+4

由於hashCode需要快速有用(因爲它主要用於防止昂貴的.equals調用),甚至數組上的淺值hashCode可能會非常緩慢。一個基本上是隨機的hashCode不會傷害,它只是沒有優勢。一小部分的罪惡。 – Torque 2013-11-28 03:31:58

4

陣列,可以使用默認的散列碼,它是基於存儲位置(但不一定內存位置,因爲它只是一個int,所有的內存地址將不適合)。你也可以通過打印System.identityHashCode(foo)的結果來看到這一點。

如果它們是相同的,相同的陣列,則陣列僅爲equal。所以,一般來說,如果數組散列碼是相同的,相同的數組,它們只會相等。

+0

(並且對象在內存中移動,並且如果您查看哈希代碼,它們通常看起來不像地址) – 2009-04-14 11:27:54

2

Object.hashCode()的默認實現實際上是返回對象的指針值,儘管這取決於實現。例如,一個64位的JVM可能會將指針和XOR以及高位和低位字組合在一起。如果有意義的話,鼓勵子類覆蓋這種行爲。

但是,在可變數組上執行相等比較沒有任何意義。如果一個元素髮生了變化,那麼這兩者不再相同。爲了保持不變,相同的數組總是返回相同的hashCode,而不管其元素髮生了什麼,數組不會覆蓋默認的hashcode行爲。

請注意,java.util.Arrays提供了一個deepHashCode()實現,用於根據數組內容而不是數組本身的身份進行哈希時的重要性。

2

我使用java.util.Arrays.hashCode(或谷歌番石榴通用包裝Objects.hashcode)同意,但如果您使用的是秦始皇知道,這可能會導致問題 - 看this link