Difference between HashMap
vs IdentityHashMap in Java
The IdentityHashMap is
one of the lesser known Map implementation
from JDK. Unlike general purposes Map implementations like HashMap and LinkedHashMap, it is very special and it's internal
working is quite different than HashMap. The main difference between IdentityHashMap and HashMap in Java is that former uses equality operator
(==) instead of equals()method to
compare keys. Which means you need the same key object to retrieve the value
from IdentityHashMap, you cannot
retrieve values by using another key which is logically equal to previous key.
Another important difference between HashMap and IdentityHashMap is
that IdentityHashMap doesn't
use hashCode() method instead it uses System.identityHashCode() method. This is a significant difference because
now you can use mutable objects as key in Map whose hash code are
likely to change when the mapping is stored inside IdentityHashMap.
Other Map implementation which uses equals() and hashCode() doesn't work well with mutable keys. For example, if you store a mapping in HashMap and then went on to change the key object the hashCode generated by key later will not be the same as before. Even if you return same, the equals() method will not return true when you compare key object from entry to given key object.
So, that's the basic difference between IdentityHashMap and a HashMap in Java, let's see a couple of more and some code to understand this concept better.
Other Map implementation which uses equals() and hashCode() doesn't work well with mutable keys. For example, if you store a mapping in HashMap and then went on to change the key object the hashCode generated by key later will not be the same as before. Even if you return same, the equals() method will not return true when you compare key object from entry to given key object.
So, that's the basic difference between IdentityHashMap and a HashMap in Java, let's see a couple of more and some code to understand this concept better.
IdentityHashMap vs HashMap in Java
As I said, IdentityHashMap is a
lesser known class from JDK, you might never use this class in your project but
a good chance is that someone else might have already used. Since most of the
programmers spend more time reading code than writing, it's important to know what is IdentityHashMap in
Java, what it does, how
it works, and when to use this class in your Java application.
Once you understand the difference between IdentityHashMap and HashMap, you will automatically learn how to make the best use of this class.
1) The first and foremost difference is that IdentityHashMap internally uses == operator instead of equals() method, which means you can store a String object into IdentityHashMap and later call the contains() method to check if it exists in the Map, it will only return true if both objects is same in heap space. It will return false even if both objects has same content, as shown below:
Once you understand the difference between IdentityHashMap and HashMap, you will automatically learn how to make the best use of this class.
1) The first and foremost difference is that IdentityHashMap internally uses == operator instead of equals() method, which means you can store a String object into IdentityHashMap and later call the contains() method to check if it exists in the Map, it will only return true if both objects is same in heap space. It will return false even if both objects has same content, as shown below:
import java.util.HashMap;
import java.util.IdentityHashMap;
import java.util.Map;
public class HashMapVsIdentityHashMap {
public static void main(String[] args) {
Map<String, Integer> idMap = new IdentityHashMap<>();
Map<String, Integer> hashMap = new HashMap<>();
String str = new String("Java");
idMap.put(str, 1);
hashMap.put(str, 1);
boolean isExist = idMap.containsKey("Java"); // false
boolean isPresent = hashMap.containsKey("Java"); // true
System.out.println("Does Java exists in IdentityHashmap?
: " + isExist);
System.out.println("Does Java exists in Hashmap? : " + isPresent);
}
}
Output:
Does
Java exist in IdentityHashmap? : false
Does
Java exist in Hashmap? : true
You need JDK 7 to run this program because we have used diamond operator (<>) to shorten the Generic code, though nothing stops you from being running it on Java SE 6 once you remove the diamond operator and specify the types on right side of initialization as well e.g.
instead of
Map<String, Integer> idMap = new IdentityHashMap<>();
use this
Map<String, Integer> idMap = new IdentityHashMap<String,
Integer>();
Using Generic is also one of the Java coding best practices which you should always follow post Java 5. You can see Java Coding Guidelines: 75 Recommendations for Reliable and Secure Programs for more of such best practices.
2) Another significant difference between HashMap and IdentityHashMap is that later uses System.identityHashCode() instead of hashCode() method of key object. This means you can also use a mutable object as a key in IdentityHashMap, which is not supported by HashMap in Java. I mean there won't be any compilation error but it will not work as expected i.e. you will not be able to retrieve object back once you modified it state because its hashCode also got changed. Let's see how this work in IdentityHashMap with an example.
Let's assume we have a class called CreditCard, which has a field called expiry, which is nothing but a formatted date in String format. Later we change the CreditCard object by changing it's expiry and see if you can find it out again from both IdentityHashMap and HashMap or not.
Java Program to show difference between HashMap vs IdentityHashMap
import java.util.HashMap;
import java.util.IdentityHashMap;
import java.util.Map;
public class sds {
public static void main(String[] args) {
CreditCard visa = new CreditCard("VISA", "04/12/2019");
CreditCard master = new CreditCard("Master", "04/11/2020");
CreditCard amex = new CreditCard("American
Express", "04/10/2021");
Map<CreditCard, String> cardToExpiry = new HashMap<>();
Map<CreditCard, String> cardToExpiryIdenity = new IdentityHashMap<>();
// inserting objects to HashMap
cardToExpiry.put(visa,
visa.getExpiryDate());
cardToExpiry.put(master,
master.getExpiryDate());
cardToExpiry.put(amex, amex.getExpiryDate());
// inserting objects to IdentityHashMap
cardToExpiryIdenity.put(visa,
visa.getExpiryDate());
cardToExpiryIdenity.put(master,
master.getExpiryDate());
cardToExpiryIdenity.put(amex, amex.getExpiryDate());
System.out.println("before modifying keys");
String result = cardToExpiry.get(visa) != null? "Yes" : "No";
System.out.println("Does VISA card exists in HashMap?
" + result);
result = cardToExpiryIdenity.get(visa) != null? "Yes" : "No";
System.out.println("Does VISA card exists in
IdenityHashMap? " + result);
// modifying value object
visa.setExpiryDate("02/11/2030");
System.out.println("after modifying keys");
result = cardToExpiry.get(visa) != null? "Yes" : "No";
System.out.println("Does VISA card exists in HashMap?
" + result);
result = cardToExpiryIdenity.get(visa) != null? "Yes" : "No";
System.out.println("Does VISA card exists in
IdenityHashMap? " + result);
}
}
class CreditCard{
private String issuer;
private String expiryDate;
public CreditCard(String issuer, String expiryDate) {
this.issuer = issuer;
this.expiryDate = expiryDate;
}
public String getIssuer() {
return issuer;
}
public String getExpiryDate() {
return expiryDate;
}
public void setExpiryDate(String expiry){
this.expiryDate = expiry;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result
+ ((expiryDate == null) ? 0 : expiryDate.hashCode());
result = prime * result + ((issuer == null) ? 0 : issuer.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
CreditCard other = (CreditCard) obj;
if (expiryDate == null) {
if (other.expiryDate != null)
return false;
} else if (!expiryDate.equals(other.expiryDate))
return false;
if (issuer == null) {
if (other.issuer != null)
return false;
} else if (!issuer.equals(other.issuer))
return false;
return true;
}
}
Output
before
modifying keys
Does
VISA card exists in HashMap? Yes
Does
VISA card exists in IdenityHashMap? Yes
after
modifying keys
Does
VISA card exists in HashMap? No
Does
VISA card exists in IdenityHashMap? Yes
From the output you can see that once you changed the CreditCard object, which is key in both HashMap and IdentityHashMap, you are not able to retrieve object in case of HashMap but you able to retrieve when you use IdentityHashMap because former uses equals() method which return different value once expiry date changed and later uses == operator which return true because in both cases the object is the same in heap.
You can also read Core Java Volume 1 - Fundamentals by Cay S. Horstmann to learn more about IdentityHashMap class in Java.
Here are some more important points about IdenityHashMap in Java:
1. It uses identity methods
i.e. equals and hashCode to retrieve values.
2. It uses reference equality
instead of equals() method i.e. object1 == object2 instead of object1.equals(object2).
3. For hashing, it uses System.identityHashCode(key) instead
of key.hashCode() as used by other Map implementations.
4. The java.util.IdenityHashMap class
is used in Serialization and deep copying, where your key is "Class"
object or interned String.
That's all about the difference between IdentityHashMap and HashMap in Java. There are rare cases where you want to use the IdentifyHashMap but it's good to know about it.
No comments:
Post a Comment