2016-04-02 6 views
0

私は2つの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文を使用して、私はそれが必要だと思うようには働いていない理由/舞台裏で何が起こっているか知りたいとき、私は奇妙な動作を得ます。私がアクセスできる特定の入力については、x、y、zと呼ばれる3つの数字を出力します。私は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です。最初の行は最初の配列の要素数で、その後にスペースで区切られた整数が続きます。 これらの次の行は、2番目の配列内の要素の数で、その後にスペースで区切られた整数が続きます。

どのように8622が同じ値を持つ唯一のキーですが、比較はfalseですか?

+1

おそらく、コメントされたバージョンはプリミティブと他のバージョンのオブジェクトを比較するためです。 – dambros

+0

どのようにしてプリミティブを比較するかは、1つの特定のキー8622を除いて問題ありません。(元のポストに入力配列を追加しました)。何が起こっているのですか、あるいは8622が他の比較と異なるのはなぜですか? – mkim123

答えて

1

オブジェクト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

わかりました。では、IntegerオブジェクトからIntegerオブジェクトへのマップなので、一般的にはfor(int i:mapA.keySet())を使うのは悪い考えですか?また、私が(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メソッドをオーバーライドする必要があります。それはプリミティブ値を等しくするにsame objectから動作を変更equalsメソッドをオーバーライドするJavaのIntegerクラスで

:ここ

// 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でオブジェクトのクラスを拡張しているのでクラスはequalsメソッドをオーバーライドします。側ノードで

、あなたがこれまでに実装&をオーバーライドする場合は、(あなたが1 &ていない他の操作を行う場合は、ほとんどのIDEのが、このと警告の自動コード生成を持つことになります)だけでなくハッシュコードを実装&を上書きするようにしてください、あなた自身に等しいです。 equalsをオーバーライドするときにハッシュコードをオーバーライドしないと、HashMap/HashSetコレクションは同じバケットにハッシュされるとは限らないため、マップ/セット内の「等しい」オブジェクトを見つけられなくなる可能性があります。

もう1つの方法は、Set操作メソッドを使用することです。 (覚えておいて、これは実際にはキーセット/基礎となるマップを変更します)

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

あなたは、元の維持/変更を気にする場合は、あなたを:あなたは、基礎となるマップに変更を気にしない場合は、あなたのような何かを行うことができます

Set<Integer> uniqKeysInA = (new HashSet<Integer>(mapA.keySet())).removeAll(mapB.keySet()) 
関連する問題