2016-04-02 30 views
0

我有兩個HashMap。 mapA.keySet()mapB.keySet()的子集。我想打印每個關鍵字mapA.get(key) != mapB.get(key)。但發生在下面的代碼中一些奇怪的行爲:如果語句後Java HashMap奇怪的行爲值發生變化

private static void printMissingNums(int[] a, int[] b) { 
    Map<Integer, Integer> mapA = intArrToMap(a); 
    Map<Integer, Integer> mapB = intArrToMap(b); 

    Set<Integer> missingNums = new TreeSet<Integer>(); 
    for (int key : mapA.keySet()) { 
     //This version does not work! 
     if (mapA.get(key) != mapB.get(key)) { 
      missingNums.add(key); 
     } 

     /* This version works (if I comment out the if statement above 
      and remove the comments around this block of code) 
     int valA = mapA.get(key); 
     int valB = mapB.get(key); 
     if (valA != valB) { 
      missingNums.add(key); 
     } 
     */ 
    } 

    // Unrelated to the strange behavior 
    for (int key : mapB.keySet()) { 
     if (!mapA.containsKey(key)) { 
      missingNums.add(key); 
     } 
    } 

    for (int i : missingNums) { 
     System.out.print(i + " "); 
    } 
} 

我得到了奇怪的行爲,當我使用的第一個if語句,想知道是怎麼回事幕後/爲什麼它,因爲我認爲它應該不工作落後。對於我可以訪問的特定輸入,它會打印3個數字,分別爲x,y,z。我檢查了HashMaps,發現mapA.get(x) != mapB.get(x)mapA.get(y) != mapB.get(y),但mapA.get(z) == mapB.get(z)

我試着在if語句之前和之後打印值,這些值是相等的,但它以某種方式進入if語句。

註釋掉的版本按我期望的那樣工作。它只打印出x和y。發生什麼事?爲什麼看起來像HashMap值正在改變,即使我沒有改變任何東西?

這是輸入:http://pastebin.com/JyYxspjx。第一行是第一個數組中的元素數量,後跟空格分隔的整數。 下一行之後是第二個數組中的元素數量,後跟空格分隔的整數。

爲什麼8622是唯一具有相同值的密鑰,但比較結果是錯誤的?

+1

可能是因爲評論版本比較了原語而其他版本的對象。 – dambros

+0

除了一個特定的鍵8622以外,怎麼比較這些原語是很好的。(我將輸入數組添加到原始帖子中)。 8622與其他比較有什麼不同? – mkim123

回答

1

請不要使用==!=代替Object compare.use equals()

流動2整數是不同的對象:

Integer i1 = new Integer(1); 
Integer i2 = new Integer(1); 
System.out.println(i1==i2);//false 

變化的if語句:

if (mapA.get(key).equlas(mapB.get(key))) { 
+0

好吧有道理。那麼使用for(int i:mapA.keySet())通常是一個糟糕的主意,因爲映射是Integer對象到Integer對象?另外,如果我決定使用(int i:mapA.keySet()),實際發生了什麼? – mkim123

+0

for(int i:mapA.keySet()):從Integer到int的自動unbox,當Integer爲null時將導致NullPointerException。 – BlackJoker

1

在比較(==foo.equals(Obj obj))的差是基於所述對象的具體實現方式的equals()方法。運營商==表示same object,在缺省情況下,.equals()進行相同的比較。您必須重寫equals方法才能更改此默認行爲。

在Java Integer類將覆蓋equals方法從same object改變行爲等同原始值:

// From the java source 
public boolean equals(Object obj) { 
    if (obj instanceof Integer) { 
     return value == ((Integer)obj).intValue(); 
    } 
    return false; 
} 

在這裏你可以看到Integer類實際上是比較類類型和平等然後原始值。在這種情況下,整數==整數比較是不同於比Integer.equals(整數)比較。

如果你很好奇,在Java Object類的equals實現是:

// From the Java source code 
public boolean equals(Object obj) { 
    return (this == obj); 
} 

因爲一切最終擴展Java中的Object類您時刻「同一對象」爲平等的,除非你的類或繼承類重寫equals方法。

在一個側面節點上,如果你曾經覆蓋&落實等於自己,一定也要重寫&實現哈希碼,以及(最IDE的將有自動代碼生成,這和警告,如果你做一個&不是其他)。當重寫equals時不覆蓋hashcode意味着你的HashMap/HashSet集合很可能在map/set中找不到「equal」對象,因爲它不一定會散列到同一個存儲桶中。

另一種方法是使用Set操作方法。如果你不關心修改底層的地圖,你可以這樣做:(記住這實際上將修改鍵集/基礎地圖)

Set<Integer> uniqKeysInA = mapA.keySet().removeAll(mapB.keyset()) 

如果你在乎修改/維持原有的,你'd需要mapA的密鑰集的防禦副本進行操作:

Set<Integer> uniqKeysInA = (new HashSet<Integer>(mapA.keySet())).removeAll(mapB.keySet())