7

I just want to be sure that my code is safe using Integer objects as keys. Here's a short example:

Integer int1 = new Integer(1337);
Integer int2 = new Integer(1337);

if (int1 == int2) {
    System.out.println("true");
} else {
    System.out.println("false");
}

if (int1.equals(int2)) {
    System.out.println("true");
} else {
    System.out.println("false");
}

Map<Integer, Object> map = new HashMap<Integer, Object>();
map.put(int1, null);
map.put(int2, null);

System.out.println(map.size());

The code will output

false
true
1

That's what I was expecting, the references differ but they equal each other. Now I'm interested in the Map's behavior.

  • Is it guaranteed that Collections like Map or Set will compare the keys by their content and not their reference?
  • Or depends it on the actual implementation, like HashMap?
Scolytus
  • 16,338
  • 6
  • 46
  • 69
  • 1
    @close: This is NOT a duplicate - the other post in question handles the matter of "equals vs. ==" whereas this question is about how well Integer will behave as an identifier in Collections! That's why there are the bullet points at the bottom. I'm asking: How do collections handle that. – Scolytus Dec 20 '12 at 09:37

8 Answers8

8

The method equals is called, hence it's the content that is compared.

As to your two questions above:

Given two objects o1 and o2 (to simplify, we assume that o1!=null and o2!=null), a hash map ultimately has to determine if they have the same value. (HashMap also checks if o1 and o2 have the same hash value, but this is not important in the context of your question). It does this by calling the method equals(). As long as o1.equals(o2) is false, the two objects are considered two different keys by HashMap.

HashSet also calls equals() to determine if an element is already contained in the set, see http://docs.oracle.com/javase/6/docs/api/java/util/HashSet.html#add%28E%29.

TreeMap, on the other hand, has to compare the two objects, and determine if they are equal, or which one if greater. It does this by calling compareTo(). Therefore, it is the return value of o1.compareTo(o2) which is important (or, if you created the tree map with the constructor http://docs.oracle.com/javase/6/docs/api/java/util/TreeMap.html#TreeMap%28java.util.Comparator%29, the comparator is used).

What is guaranteed is therefore that in HashMap and HashSet, the method equals() is used to tell objects apart, and in TreeMap, the method compareTo(). Other Map implementations may use == (such as IdentityHashMap).

Alec Henninger
  • 360
  • 3
  • 12
gefei
  • 18,922
  • 9
  • 50
  • 67
  • It actually depends on the implementation of equals method. You can compare by reference in the equals method anyway. – nhahtdh Dec 19 '12 at 12:36
  • How about hashcode() method. Though equals return true and if hashcode() values are different, still these two keys are same.? – Vallabh Patade Dec 19 '12 at 12:42
  • 1
    @VallabhPatade: Contract of `hashCode`: `If two objects are equal according to the equals(Object) method, then calling the hashCode method on each of the two objects must produce the same integer result.` You are free to break the contract, but the application depends on it will break. – nhahtdh Dec 19 '12 at 12:45
  • You mean if two objects are "equals()" then no mater what value does "hashcode()" returns, these two objects are same keys in case of hashmap. – Vallabh Patade Dec 19 '12 at 12:58
  • You were the first to answer, and basically your answer is correct. Would you elaborate a bit more on the two questions I've raised (the bullet point on the bottom) Then I'll happily accept your answer. – Scolytus Dec 20 '12 at 09:56
6

Q1: - Is it guaranteed that Collections like Map or Set will compare the keys by their content and not their reference?

A1: - No. Collection, Map and Set are interfaces. Only thing that they assure is the contract of possible methods.

Q2: - Depends it on the actual implementation, like HashMap?

A2: Yes. How class deals with comparation it is a developer decision.

HashMap use two things to allocate their objects

First - is Object#hashCode(), that is used to calculate index.

Second - is Object#equals(), that is used then hash colision have places.

3

If you open implementation of java.util.AbstractMap you can see that keys and values equation is checked using Object#equals method everywhere. What actually will be compared inside map depends on key/value implementation of Object#equals method.

bellum
  • 3,642
  • 1
  • 17
  • 22
1

Here Integer is Waraper final class, which is overriden equals() method so it will compare only content.

So If use Integers are Any wrapper class there is no problem in Map

Suppose if You want use Custome Class as key You need override equals() and hashcode() method to avoid duplicates in Map

NPKR
  • 5,368
  • 4
  • 31
  • 48
  • 1
    Not generally true, you could easily have a final class that overrides `equals()` and still test on object equality rather than content equality... – Anders R. Bystrup Dec 19 '12 at 12:41
  • Integer Class is final class, but it has compaered the content only. it means we can not override this Integer class methods to change behavier. – NPKR Dec 19 '12 at 12:44
  • Maybe you should mention that Maps in generally call the equals method to determine the equality of keys - that's what I was asking for ;) – Scolytus Dec 20 '12 at 09:51
0

It actually depend on the equals() implementation of the K/key you specify for the Map.

Try doing the same with a Map<Object,String> and see what happens (hint: for Object's to be equal they actually have to be the same object)

Cheers

Anders R. Bystrup
  • 15,729
  • 10
  • 59
  • 55
0

The first compares two different objects (references) --> false.

The second compares (equal) the values of these objects --> true

Hashmap uses the equals and hascode methods of objects to determine unique keys. so you have the same key inserted twice resulting in one remaining element. the second one. have a look at Map#put javadoc to see whats happening.

semTex
  • 343
  • 5
  • 16
  • That's not exactly what I was asking, but the javadoc gave me a clue. The important part is in .containsKey() where it is specified to use .equals() – Scolytus Dec 20 '12 at 09:50
0

In case of hashmap, keys are compared using equals() and hashcode() methods.

In example above, both hashcode() and equals() and overridden in Integer class. When HashMap compares two keys, first it takes hashcode() of that object and then call equals method on this object and the key having same hashcode value.

Vallabh Patade
  • 4,960
  • 6
  • 31
  • 40
  • That's not an exact answer to my question. – Scolytus Dec 20 '12 at 09:45
  • It's not an answer to my question. But it looks like my question is not easy to understand, though. (At least people don't get the point.) My main interest are the two bullet points at the end of the question which are barely answered by anybody. Anyhow, thanks to the sum of all answers, I figured it out already. All Maps are supposed to call equals() for key comparison. Maybe I'll edit the question to clean it up, I thought more context would be good... – Scolytus Dec 20 '12 at 23:58
0

When putting an item inside a HashMap (and HashSet by extension) hashCode is used (transformed by a simple linear function) to determine where the item should be placed inside it's internal collection.

Then in the determined location it searches for an identical object (among all items stored there) using (o1 == o2 || o1.equals(o2)), the #equals function is called if references differ, which is a performance improvement to simple #equals call. If identical item is found, its assigned value is replaced with the new one, if not, the new item is simply added to internal collection.