[英]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.