Every Java developer uses HashMap. Far fewer can explain what actually happens when you call put() or get(). Here's what's going on under the hood.
I animated the whole thing below 👇 — writeup underneath.
From key to bucket
When you put a key in:
- HashMap calls the key's hashCode() to get an int.
- It spreads the bits (to reduce clustering) and maps it to one of N buckets — essentially hash & (N - 1).
- The entry is stored in that bucket.
get() runs the same math to jump straight to the right bucket. That's why average lookups are O(1) — no scanning the whole map.
Collisions
Two different keys can land in the same bucket. HashMap handles this with separate chaining — a linked list inside the bucket. Since Java 8, once a single bucket gets long enough (8+ entries), it converts that list into a balanced tree, so a worst-case bad-hash scenario degrades to O(log n) instead of O(n).
Resizing (rehashing)
A HashMap has a load factor (default 0.75). Once it's ~75% full, it doubles the bucket array and rehashes every entry into the bigger table. This keeps buckets short and lookups fast — but a resize is an expensive, occasional cost.
Why it matters in practice
- equals() and hashCode() must agree. Break that contract and keys effectively "disappear" — you store with one and can't retrieve with an equal one.
-
Size it up front for large inserts (
new HashMap<>(expectedSize)) to avoid repeated resizes.
I make animated breakdowns like this — data structures, system design & backend, visualized — on CodeAnimated.
â–¶ Full channel: https://www.youtube.com/@CodeAnimatedDev
Top comments (0)