Reputation: 63
I had an interview today, and I got the following Java code:
public class Question_6 {
public static void main(String[] args){
Map<Integer,String> map1 = new HashMap<Integer,String>();
map1.put(new Integer(1),"001a");
map1.put(new Integer(1),"001b");
map1.put(new Integer(2),"002");
System.out.println(map1.size());
Map<MyInt,String> map2 = new HashMap<MyInt,String>();
map2.put(new MyInt(1),"001a");
map2.put(new MyInt(1),"001b");
map2.put(new MyInt(2),"002");
System.out.println(map2.size());
}
}
public class MyInt {
int i;
public MyInt(int i) {
this.i = i;
}
}
The questions were:
What will be printed to the console?
Suggest a solution to the problem.
I know now that the answer to the first question is :
2
3
But I don't know why? What is the problem with MyInt
?
Upvotes: 4
Views: 8743
Reputation: 1
For the Integer class, By Default The Integer class caches integer values from -127 to 127. Therefore, the Integer objects can only be created in the range -128 to 127.
map1.put(new Integer(1),"001a");// new entry created in hashmap map1.put(new Integer(1),"001b");// "001b" overrides "001a" value in hashmap map1.put(new Integer(2),"002");// new entry created in hashmap
So overall size of hashmap will be 2.
Upvotes: 0
Reputation: 162
The Integer class overrides the equals() method to do value-based comparison.No need to manually include equals() or hashcode() methods. My solution is as follows
import java.util.HashMap;
import java.util.Map;
public class HashMapEqualsHashcode {
public static void main(String[] args) {
MyInt obj = new MyInt(50);
Map<Integer, String> map1 = new HashMap<Integer, String>();
map1.put(new Integer(1),"001a");
map1.put(new Integer(1),"001b");
map1.put(new Integer(2),"002");
System.out.println("map1 size "+map1.size());
Map<MyInt,String> map2 = new HashMap<MyInt,String>();
map2.put(new MyInt(1),"001a");
map2.put(new MyInt(1),"001b");
map2.put(new MyInt(2),"002");
System.out.println("map2 size "+map2.size());
}
}
class MyInt {
int i;
public MyInt(int i) {
this.i = i;
}
}
Screenshot for the solution
https://i.sstatic.net/yVkgL.png
Upvotes: 1
Reputation: 125
The Integer class overrides the equals() method to do value-based comparison. Hashmaps cannot contain two keys that are "equal", so the 2nd insertion into map1 will overwrite the first entry. As well, the hashcode() method is overridden.
However, Myint does not override the equals() or hashcode() method so equality is memory location-based. Therefore, map2 sees three distinct keys and makes three distinct entries.
Upvotes: 0
Reputation: 15758
Your problem is that equals()
and hashcode()
is not implemented on MyInt
.
You are expected to have 2
as a result in both cases.
HashMap
, as the name implies, groups the keys into buckets based on the keys' hashcode(). But the default hashcode does not match for two instances of MyInt
with the same value.
To determine equality, you have to override equals()
as well.
One solution:
public class MyInt {
[...]
@Override
public int hashCode() {
return value;
}
@Override
public boolean equals(Object obj) {
if (obj instanceof MyInt) {
return i == ((MyInt)obj).i;
}
return false;
}
}
Upvotes: 12
Reputation: 54722
You must override the hashCode()
and equals
methods. For all cases where equals returns true for two objects, hashCode returns the same value. The hash code is a code that must be equal if two objects are equal
Why??
if you inspect in the source code of HashMap.put method. you can see that this method check both hashcode
and equality
before inserting. So if you don't override these methods it will use the superclass' (object's) methods which will return different values for different objects. So ALthough for the same key two values will be inserted in separate place of Hashmap
. So you need to override those two and make sure that for two equal objects you should return same hashcode
.
Code
So your MyInt should be something like
public class MyInt {
int i;
public MyInt(int i) {
this.i = i;
}
public int hashCode() {
return i;
}
public boolean equals(Object obj) {
if (obj instanceof MyInt && i == ((MyInt)obj).i) {
return true;
} else
return false;
}
}
Upvotes: 0
Reputation: 1572
map1.put(new Integer(1),"001a");
map1.put(new Integer(1),"001b");//same location in map
map1.put(new Integer(2),"002");
in this part you use the Integer class, Integer class don't allow setting the same location, but your Integer class allow.
Change code like this, and you see the problem
public class Question_6 {
public static void main(String[] args){
Map<Integer,String> map1 = new HashMap<Integer,String>();
map1.put(new Integer(1),"001a");
map1.put(new Integer(2),"001b");
map1.put(new Integer(3),"002");
System.out.println(map1.size());
Map<MyInt,String> map2 = new HashMap<MyInt,String>();
map2.put(new MyInt(1),"001a");
map2.put(new MyInt(2),"001b");
map2.put(new MyInt(3),"002");
System.out.println(map2.size());
}
this code will print ;
3 3
So, your Integer class(myInt) is true but missing
Upvotes: 1
Reputation: 1881
The Integer class overrides the equals()
method to do value based comparison. Hashmaps cannot contain two keys that are "equal", so the 2nd insertion into map1 will overwrite the first entry. As well, the hashcode()
method is overridden.
However, MyInt does not override the equals()
or hashcode()
method so equality is memory location based. Therefore, map2 sees three distinct keys and makes three distinct entries.
Map<MyInt,String> map2 = new HashMap<MyInt,String>();
MyInt one = new MyInt(1);
MyInt two = new MyInt(2);
map2.put(one,"001a");
map2.put(one,"001b");
map2.put(two,"002");
System.out.println(map2.size());
Produces an output of 2
in this case because one.equals(one) is true in this case.
Upvotes: 2
Reputation: 49422
You need to override the equals()
and hashCode()
method in your MyInt
class , so that HashMap
can comprehend new MyInt(1).equals(new MyInt(1))
is true
.
Upvotes: 3