Cấu trúc lõi: mảng bucket; entry được đặt vào bucket theo hash(key) & (n - 1) (n = capacity, luôn là lũy thừa của 2).
put(key, value):
1. Tính hash từ hashCode() của key (JDK trộn thêm bit cao để giảm collision).
2. Định vị bucket. Bucket trống → đặt node mới.
3. Bucket đã có node → collision: duyệt so equals() — trùng key thì ghi đè value, không trùng thì nối vào linked list của bucket.
Treeify (Java 8+): list trong 1 bucket dài quá 8 (và mảng ≥ 64) → chuyển thành red-black tree → lookup worst case từ O(n) xuống O(log n) — chống cả tấn công hash collision.
Resize: số entry vượt capacity × load factor (default 0.75) → nhân đôi mảng, phân bổ lại entry.
Hệ quả thực dụng: key phải override đúng cặp hashCode()/equals() (xem câu contract) và nên immutable — key bị sửa làm đổi hashCode sau khi put thì entry "biến mất" (nằm sai bucket, không tìm lại được).
Core structure: a bucket array; entries land in a bucket via hash(key) & (n - 1) (n = capacity, always a power of 2).
put(key, value):
1. Compute the hash from the key's hashCode() (the JDK mixes in high bits to reduce collisions).
2. Locate the bucket. Empty → place a new node.
3. Bucket occupied → collision: walk the nodes comparing equals() — same key overwrites the value, different key appends to the bucket's linked list.
Treeify (Java 8+): a bucket's list longer than 8 (with array ≥ 64) → converted to a red-black tree → worst-case lookup drops from O(n) to O(log n) — also defends against hash-collision attacks.
Resize: entry count exceeding capacity × load factor (default 0.75) → array doubles, entries are redistributed.
Practical consequence: keys must correctly override the hashCode()/equals() pair (see the contract item) and should be immutable — mutating a key so its hashCode changes after put makes the entry "vanish" (wrong bucket, unreachable).