
HashMap 本质是个数组加链表(或红⿊树)的结构,存数据靠 key 的 hash 值定位桶位置。数组初始⻓度是 16,负载因⼦默认 0.75,到 12 个元素就扩容,避免冲突太多影响性能。
key 的 hash 值不是直接⽤,⽽是再做⼀次扰动运算,把⾼位也参与映射,减少碰撞概率。定位桶⽤ (n - 1) & hash ⽽不是取模,位运算更快。
1)数组⾥每个桶刚开始是 Node 节点,链表⻓度超过 8 且数组⻓度⼤于等于 64,链表转成红⿊树,防⽌极端情况下查询退化成 O(n)
2)如果⻓度⼩于 6,即使 hash 冲突严重也先不转树,因为数组太⼩扩容更划算
3)删除节点时树⻓度⼩于 6 ⼜会转回链表
put 操作流程:算 hash → 找桶 → 空则新建,否则遍历链/树插⼊ → 判断是否扩容。get 就反过来查。
注意多线程下 put 可能导致环形链表,所以 hashMap 是非线程安全,并发场景得⽤ ConcurrentHashMap。JDK 8 虽然优化了扩容时的头插改尾
插,但依然不能保证线程安全。