Reputation: 8671
Could anyone please tell what are the important use cases of IdentityHashMap
?
Upvotes: 68
Views: 20078
Reputation: 863
One notable use case that is not mentioned in the answers is if you have mutable objects as keys in your Map.
Say for example you have a Map<Person, Integer> where Person is a POJO with an all-parameter constructor AND an overriden equals()
and hashCode()
methods.
In this case, you cannot use a HashMap
to store your Person
objects, and the IdentityHashMap
comes to a rescue.
Map<Person, Integer> hMap = new HashMap<>();
Map<Person, Integer> iMap = new IdentityHashMap<>();
Person john = new Person("John", "Doe", "123-45-6789");
hMap.put(john, 100_000);
iMap.put(john, 100_000);
System.out.println(hMap.containsKey(john)); // true
System.out.println(iMap.containsKey(john)); // true
// modify the key object
john.fname = "Jane";
System.out.println(hMap.containsKey(john)); // false
System.out.println(iMap.containsKey(john)); // true
hMap.put(john, 200_000);
iMap.put(john, 200_000);
System.out.println(hMap.size()); // 2
System.out.println(iMap.size()); // 1
Note how the HashMap
has two objects after the add, while the IdentityHashMap
has only one. This is because the modified object ("John Doe" vs "Jane Doe") has a different hashCode
. But because it is still the same object, the put()
to the IdentityHashMap
simply overrides the existing Entry.
And also note that, if you do not override the hashCode()
method in the class you use as the key, JVM will use the identityHashCode by default, and both Map implementations will behave similarly.
PS: it is usually a bad idea to use mutable keys in a map.
Upvotes: 0
Reputation: 4932
HashMap creates Entry objects every time you add an object, which can put a lot of stress on the GC when you've got lots of objects. In a HashMap with 1,000 objects or more, you'll end up using a good portion of your CPU just having the GC clean up entries (in situations like pathfinding or other one-shot collections that are created and then cleaned up). IdentityHashMap doesn't have this problem, so will end up being significantly faster.
See a benchmark here: http://www.javagaming.org/index.php/topic,21395.0/topicseen.html
Upvotes: 19
Reputation: 418565
You can also use the IdentityHashMap
as a general purpose map if you can make sure the objects you use as keys will be equal if and only if their references are equal.
To what gain? Obviously it will be faster and will use less memory than using implementations like HashMap
or TreeMap
.
Actually, there are quite a lot of cases when this stands. For example:
Enum
s. Although for enums there is even a better alternative: EnumMap
Class
objects. They are also comparable by reference.String
s. Either by specifying them as literals or calling String.intern()
on them.Integer.valueOf(int)
:
This method will always cache values in the range -128 to 127, inclusive...
To demonstrate the last point:
Map<Object, String> m = new IdentityHashMap<>();
// Any keys, we keep their references
Object[] keys = { "strkey", new Object(), new Integer(1234567) };
for (int i = 0; i < keys.length; i++)
m.put(keys[i], "Key #" + i);
// We query values from map by the same references:
for (Object key : keys)
System.out.println(key + ": " + m.get(key));
Output will be, as expected (because we used the same Object
references to query values from the map):
strkey: Key #0
java.lang.Object@1c29bfd: Key #1
1234567: Key #2
Upvotes: 25
Reputation: 5080
Whenever you want your keys not to be compared by equals
but by ==
you would use an IdentityHashMap. This can be very useful if you're doing a lot of reference-handling but it's limited to very special cases only.
Upvotes: 41
Reputation: 147164
One important case is where you are dealing with reference types (as opposed to values) and you really want the correct result. Malicious objects can have overridden hashCode
and equals
methods getting up to all sorts of mischief. Unfortunately, it's not used as often as it should be. If the interface types you are dealing with don't override hashCode
and equals
, you should typically go for IdentityHashMap
.
Upvotes: 5
Reputation: 5876
One case where you can use IdentityHashMap is if your keys are Class objects. This is about 33% faster than HashMap for gets! It probably uses less memory too.
Upvotes: 27
Reputation: 139
This is a practical experience from me:
IdentityHashMap leaves a much smaller memory footprint compared to HashMap for large cardinalities.
Upvotes: 13
Reputation: 4978
The documentations says:
A typical use of this class is topology-preserving object graph transformations, such as serialization or deep-copying. To perform such a transformation, a program must maintain a "node table" that keeps track of all the object references that have already been processed. The node table must not equate distinct objects even if they happen to be equal. Another typical use of this class is to maintain proxy objects. For example, a debugging facility might wish to maintain a proxy object for each object in the program being debugged.
Upvotes: 30