簡體   English   中英

Java HashMap的奇怪行為值在if語句后更改

[英]Java HashMap strange behavior value changing after if statement

我有兩個HashMap。 mapA.keySet()的一個子集mapB.keySet() 我想打印mapA.get(key) != mapB.get(key) 但是下面的代碼中發生了一些奇怪的行為:

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?

不要將==!=用於對象比較,而應使用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))) {

比較中的差異( ==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 == Integer比較不同於 Integer.equals(Integer)比較。

如果您感到好奇,那么Java Object類等於實現是:

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

由於所有內容最終都會擴展java中的Object類,因此除非您的類或繼承的類重寫equals方法,否則始終會得到等於“相同對象”的equals。

在一個側面節點上,如果您覆蓋並實現等於您的自己,請確保也覆蓋並實現哈希碼(大多數IDE會為此自動生成代碼,並且如果您選擇一個而不是另一個,則會發出警告)。 覆蓋等於時不覆蓋哈希碼的后果是,您的HashMap / HashSet集合可能不會在映射/集中找到“等於”對象,因為它不一定會哈希到同一存儲桶中。

另一種方法是使用Set操作方法。 如果您不關心對基礎地圖的修改,則可以執行以下操作:(請記住,這實際上會修改鍵集/基礎地圖)

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

如果您關心修改/維護原始文檔,則需要一份防御性的mapA鍵集副本才能進行以下操作:

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM