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:
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>();
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:
- It uses identity methods i.e. equals and hashCode to retrieve values.
- It uses reference equality instead of equals() method i.e. object1 == object2 instead of object1.equals(object2).
- For hashing, it uses System.identityHashCode(key) instead of key.hashCode() as used by other Map implementations.
- 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