WeakHashMap and IdentityHashMap in Java

Naveen AnamaneniUpdated · 4 min read

WeakHashMap and IdentityHashMap are two special-purpose Map implementations in java.util. WeakHashMap holds its keys weakly: when a key is no longer used anywhere else in the program, the garbage collector may remove it, and its entry disappears from the map. IdentityHashMap compares keys with == (the same object) instead of equals (equal content). They are rarely needed, but they solve a few problems no other map can. In this lesson, you will learn how each works and when to use it.

WeakHashMap

A normal HashMap keeps a strong reference to each key, so a key stays in memory as long as it is in the map, even if nothing else uses it. A WeakHashMap keeps a weak reference: if the only remaining reference to a key is the map's, the garbage collector is allowed to free the key, and the map then removes that entry automatically.

Features of WeakHashMap

  • Entries vanish when their keys are garbage collected.
  • Useful for caches and metadata attached to objects owned elsewhere.
  • Allows null keys and values.
  • Not synchronized.
  • Its size can change between two calls without your code touching it.

Example: An Entry Disappears

Let's see an example where a key loses its last outside reference. Garbage collection can't be forced, only requested, so the output may differ between runs.

WeakDemo.java▶ Try it
import java.util.Map;
import java.util.WeakHashMap;
 
public class WeakDemo {
    public static void main(String[] args) throws InterruptedException {
        Map<Object, String> cache = new WeakHashMap<>();
        Object navikaKey = new Object();
        Object srihithaKey = new Object();
        cache.put(navikaKey, "Navika's thumbnail");
        cache.put(srihithaKey, "Srihitha's thumbnail");
        System.out.println("Before: " + cache.size() + " entries");
 
        navikaKey = null;
        System.gc();
        Thread.sleep(100);
 
        System.out.println("After:  " + cache.size() + " entries");
        System.out.println("Srihitha still cached? "
            + cache.containsKey(srihithaKey));
    }
}
Output
Before: 2 entries
After:  1 entries
Srihitha still cached? true

Explanation: Setting navikaKey to null removed the last strong reference to that key object. After the garbage collector ran, the map dropped its entry. srihithaKey is still used by the program, so its entry stays.

Choosing Keys for a WeakHashMap

IdentityHashMap

IdentityHashMap breaks the normal Map rule on purpose: two keys are the same only if they are the same object (k1 == k2). It uses System.identityHashCode instead of the key's hashCode.

Features of IdentityHashMap

  • Compares keys with ==, not equals.
  • Useful for tracking objects themselves: for example, "have I already visited this exact object?" when copying or serializing a graph of objects.
  • Allows null keys and values.
  • Not synchronized.

Example: Equal Strings, Different Objects

IdentityDemo.java▶ Try it
import java.util.HashMap;
import java.util.IdentityHashMap;
import java.util.Map;
 
public class IdentityDemo {
    public static void main(String[] args) {
        String a = new String("Navika");
        String b = new String("Navika");
        System.out.println("a.equals(b): " + a.equals(b)
            + ", a == b: " + (a == b));
 
        Map<String, Integer> normal = new HashMap<>();
        normal.put(a, 1);
        normal.put(b, 2);
        System.out.println("HashMap size: " + normal.size());
 
        Map<String, Integer> identity = new IdentityHashMap<>();
        identity.put(a, 1);
        identity.put(b, 2);
        System.out.println("IdentityHashMap size: " + identity.size());
    }
}
Output
a.equals(b): true, a == b: false
HashMap size: 1
IdentityHashMap size: 2

Explanation: a and b have the same characters but are two different objects. HashMap uses equals, so it treats them as one key and keeps size 1. IdentityHashMap uses ==, so it stores two entries.

Comparison

HashMapWeakHashMapIdentityHashMap
Key comparisonequalsequals==
Hash usedhashCode()hashCode()System.identityHashCode()
Keeps keys aliveYesNoYes
Typical useGeneral purposeCaches tied to object lifetimeTracking exact objects

Common Mistakes

Using WeakHashMap as a general-purpose cache. Entries disappear only when keys are collected, not when memory is low by your rules; use a caching library for size or time limits.

Using IdentityHashMap with strings or numbers you look up by value. Equal values in different objects won't be found.

Practice

  1. Easy: Change IdentityDemo to use the string literal "Navika" for both a and b. What sizes are printed, and why?
  2. Harder: Use an IdentityHashMap<Object, Boolean> to count how many distinct objects are in a list that contains some objects more than once and some equal-but-separate objects.

Quick check: WeakHashMap and IdentityHashMap

4 questions
1When can a WeakHashMap entry disappear?
2How does IdentityHashMap compare keys?
3Two new String("x") keys go into an IdentityHashMap. What is its size?
4Why avoid string literals as WeakHashMap keys?

Key Takeaways

Was this tutorial helpful?

Lesson 291 of 482