Java HashMap奇怪的行为值在if语句之后发生变化

时间:2016-04-02 01:00:35

标签: java hashmap key

我有两个HashMaps。 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是唯一具有相同值但比较为假的键?

2 个答案:

答案 0 :(得分:1)

请勿使用==!=进行对象比较。请改为使用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))) {

答案 1 :(得分: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 == Integer比较不同比Integer.equals(整数)比较。

如果您感到好奇,Java Object类等于实现是:

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

因为一切都最终扩展了java中的Object类,所以你总是得到同样的对象&#34; for equals除非你的类或继承的类重写equals方法。

在侧节点上,如果您曾覆盖&amp;实现等于你自己,一定要覆盖&amp;同时实现哈希码(大多数IDE都会为此生成自动代码,如果你选择另一个则不会发出警告)。覆盖equals时不覆盖哈希码的结果意味着你的HashMap / HashSet集合可能找不到&#34;等于&#34; map / set中的对象,因为它不一定会散列到同一个桶中。

另一种方法是使用Set操作方法。如果您不关心对底层地图的修改,您可以执行以下操作:(请记住,这实际上会修改键集/底层地图)

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

如果您关心修改/维护原件,您需要使用mapA的密钥集的防御性副本进行操作:

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