views:

499

answers:

7

Hello I am using this code to check that array is present in the HashMap.

public class Test {
    public static void main(String[]arg)
    {
     HashMap<int[],String> map= new HashMap<int[],String>();
     map.put(new int[]{1,2}, "sun");
     System.out.println(map.containsKey((new int[]{1,2})));
    }
}

But this prints False. How can I check that array is present in the HashMap. Thanks in advance.

+2  A: 

I think the problem is your array is doing an '==' comparison, i.e. it's checking the reference. When you do containsKey(new int[] { ... }), it's creating a new object and thus the reference is not the same.

If you change the array type to something like ArrayList<Integer> that should work, however I would tend to avoid using Lists as map keys as this is not going to be very efficient.

Phill Sacre
Thank you sir for your answer
Sunil
+5  A: 

You are comparing two difference references - notice the double use of new. Something like this will work:

public class Test {
    public static void main(String[] arg)
    {
     HashMap<int[],String> map= new HashMap<int[],String>();
     int[] a = new int[]{1,2};
     map.put(a, "sun");
     System.out.println(map.containsKey(a));
    }
}

Since a is the same reference, you will receive true as expected. If your application has no option of passing references to do the comparison, I would make a new object type which contains the int[] and override the equals() method (don't forget to override hashCode() at the same time), so that will reflect in the containsKey() call.

Yuval A
Implementing only `equals()` is **not** enough, you need to implement `hashCode()` as well. See Chapter 3 of Effective Java (available online: http://java.sun.com/developer/Books/effectivejava/Chapter3.pdf)
Joachim Sauer
Thank you sir for your answer
Sunil
@Joachim, thanks for the clarification.
Yuval A
+1  A: 

You've got two different objects that happen to contain the same values, because you've called new twice.

One approach you might use is to create a "holder" class of your own, and define that class's equals and hash methods.

djna
Thank you sir for answer
Sunil
+1  A: 

Are you sure you don't want to map Strings to arrays instead of the other way around?

Anyway, to answer your question, the problem is you are creating a new array when you call containsKey(). This returns false between you you have two separately newed arrays that happen to have the same elements and dimension. See Yuval's answer to see the correct way of checking if an array is contained as a key.

An alternative, more advanced, approach is to create your own class that wraps an array and overwrites hashCode() so that two arrays with the same dimension and elements will have equal hash codes.

Justin Ardini
Thanks for your Response..
Sunil
+2  A: 

The hashCode() implementation for arrays is derived from Object.hashCode(), so it depends on the memory location of the array. Since the two arrays are instantiated separately, they have different memory locations and thus different hashcodes. If you made one array it would work:

int[] arr = {1, 2};
map.put(arr, "sun");
System.out.println(map.containsKey(arr));
Michael Mrozek
Thanks for your Response..
Sunil
+5  A: 

The problem is because the two int[] aren't equal.

System.out.println(
    (new int[] { 1, 2 }).equals(new int[] { 1, 2 })
); // prints "false"

Map and other Java Collections Framework classes defines its interface in terms of equals. From Map API:

Many methods in Collections Framework interfaces are defined in terms of the equals method. For example, the specification for the containsKey(Object key) method says: "returns true if and only if this map contains a mapping for a key k such that (key==null ? k==null : key.equals(k))."

Note that they don't have to be the same object; they just have to be equals. Arrays in Java extends from Object, whose default implementation of equals returns true only on object identity; hence why it prints false in above snippet.


You can solve your problem in one of many ways:

  • Define your own wrapper class for arrays whose equals uses java.util.Arrays equals/deepEquals method.
    • And don't forget that when you @Override equals(Object), you must also @Override hashCode
  • Use something like List<Integer> that does define equals in terms of the values they contain
  • Or, if you can work with reference equality for equals, you can just stick with what you have. Just as you shouldn't expect the above snippet to ever print true, you shouldn't ever expect to be able to find your arrays by its values alone; you must hang-on to and use the original references every time.

See also:

API

  • Object.equals and Object.hashCode
    • It's essential for a Java programmer to be aware of these contracts and how to make them work with/for the rest of the system
polygenelubricants
Thanks Sir for your Answer
Sunil
+2  A: 

I would use a different approach. As mentioned before, the problem is with arrays equality, which is based on reference equality and makes your map useless for your needs. Another potential problem, assuming that you use ArrayList instead, is the problem of consistency: if you change a list after is has been added to the map, you will have a hashmap corruption since the position of the list will not reflect its hashcode anymore.

In order to solve these two problems, I would use some kind of immutable list. You may want to make an immutable wrapper on int array for example, and implement equals() and hashCode() yourself.

Eyal Schneider
Thanks for your Answer
Sunil