What happens inside HashMap.put()?
Mediumput() hashes the key, folds the high bits into the low bits, and uses (n - 1) & hash to pick a bucket. Empty bucket: store it. Otherwise match by hash + equals() and replace, or append. Crowded buckets turn into trees; past 75% full the table doubles.
How it works
- Hash.
putcallskey.hashCode()and XORs the top 16 bits into the bottom 16 (h ^ (h >>> 16)). Keys whose hashes differ only in high bits still spread across a small table. - Pick a bucket. Table length is always a power of two, so
(length - 1) & hashis a cheap modulo. - Empty bucket: the new node goes straight in.
- Occupied bucket: walk its nodes. A node with the same hash and an
equals()key gets its value replaced, andputreturns the old value. Otherwise the new node is appended. - Treeify. A bucket with 8 or more nodes becomes a red-black tree, but only when the table has at least 64 slots. Smaller tables resize instead.
- Resize. Once the entry count passes
capacity × loadFactor(16 × 0.75 = 12 by default), the table doubles. Each node either keeps its index or moves toindex + oldCapacity.
Example
Map<String, Integer> stock = new HashMap<>();
stock.put("apple", 10); // null: new key
Integer before = stock.put("apple", 7); // 10: value replaced
stock.put(null, 0); // allowed, lives in bucket 0A key class without equals/hashCode breaks lookups:
class Sku { final String code; Sku(String code) { this.code = code; } }
Map<Sku, Integer> qty = new HashMap<>();
qty.put(new Sku("A1"), 5);
qty.get(new Sku("A1")); // null: identity hash puts it in another bucket
record SkuKey(String code) {} // records generate equals/hashCode, so lookups workEdge cases
- One
nullkey is allowed; its hash is treated as 0. - Changing a field used by
hashCode()after inserting the key strands the entry: it sits in the old bucket and lookups miss it. - Inside a tree bucket, nodes are ordered by hash, then by
compareTowhen keys areComparable. - Presize when you know the count:
HashMap.newHashMap(1_000)(Java 19+) avoids repeated resizing.
Common mistakes
- Saying the map treeifies at 8 entries total. It's 8 in one bucket, and only once the table is 64+ slots.
- Overriding
equals()but nothashCode(). - Expecting insertion order. Use
LinkedHashMapfor that.
Likely follow-up
"How is ConcurrentHashMap.put() different?" Empty bins are filled with a CAS, busy bins lock only their first node, there's no map-wide lock, and null keys or values are rejected.
Get every deep dive in the app
Coming soon to the App StoreComing soon to Google Play