Java面试高频考点:HashMap核心机制

张开发
2026/4/9 16:27:16 15 分钟阅读

分享文章

Java面试高频考点:HashMap核心机制
问为什么哈希 / 扰动函数能降低 hash 碰撞答对原始哈希值做二次变换打散高位特征让高位参与索引计算避免高位不同低位相同使哈希值分布更均匀减少哈希碰撞概率充分利用 32 位哈希值的所有位信息记忆口诀扰动打散高位减少哈希碰撞问HashMap 的扰动函数是怎么实现的答实现为 h key.hashCode () ^ (h 16)将哈希值右移 16 位与原哈希值异或让高位特征融入低位提升分布均匀性是轻量级的二次哈希性能开销极低记忆口诀右移 16 位高低位异或问HashMap 为什么用 运算代替 % 取模答数组长度为 2 的幂次时(n-1)hash 等价于 hash% n位运算 的执行效率远高于取模运算 %大幅提升哈希索引的计算性能配合扰动函数保证索引分布均匀记忆口诀 比 % 快2 的幂次等价问HashMap 的 get 实现是怎样的答计算 key 的哈希值通过 hash(length-1) 定位桶检查桶首节点匹配则直接返回对应 value首节点是 TreeNode 则用红黑树查找否则遍历链表找到匹配 key 返回 value未找到返回 null记忆口诀哈希定位先查首树链分查问HashMap 的 get 方法时间复杂度是多少答无哈希冲突时时间复杂度为 O (1)存在链表时最坏时间复杂度为 O (n)转为红黑树后最坏时间复杂度为 O (log n)平均时间复杂度为 O (1)性能极高记忆口诀平均 O (1)最坏 O (log n)问HashMap 查找时为什么先比较哈希再比较 equals答哈希值比较是数值比较执行速度极快哈希不同则 key 一定不同可快速排除不匹配哈希相同才需要调用 equals 做精确比较大幅减少 equals 调用次数提升查找性能记忆口诀先比哈希快排错再比 equals 精确匹配问解决哈希冲突有哪些方法呢答链地址法冲突元素存入同一桶的链表 / 红黑树线性探测冲突时顺序查找下一个空槽位双重哈希用两个哈希函数计算下一个位置公共溢出区冲突元素统一存入公共溢出区记忆口诀链探双溢解决冲突问HashMap 采用哪种方法解决哈希冲突答采用链地址法作为核心冲突解决方法冲突元素先以链表存储在对应桶中链表长度超 8 且数组≥64转为红黑树红黑树节点数 6退化为链表记忆口诀HashMap 用链地址链树互转问链地址法和线性探测的核心区别是什么答链地址法冲突元素存链表线性探测存数组链地址法无聚集问题线性探测易产生聚集链地址法适合频繁增删线性探测适合查询链地址法需额外指针空间线性探测不用记忆口诀链法无聚集探测易聚集问HashMap 是线程安全的吗多线程下会有什么问题答HashMap 不是线程安全的是非同步数据结构JDK7 扩容头插法可能导致环形链表死循环多线程同时 put 可能导致元素覆盖丢失扩容时并发 get 可能返回 null记忆口诀HashMap 非线程安全死循环丢数据问怎么保证 HashMap 的线程安全答使用 ConcurrentHashMap 替代高并发首选使用 Collections.synchronizedMap 包装手动加 synchronized 锁或其他同步机制使用 ThreadLocal 维护线程私有实例记忆口诀替代、包装、加锁、线程私有问JDK8 的 HashMap 解决了什么线程安全问题答扩容改用尾插法解决环形链表死循环但仍存在元素覆盖、get 返回 null 问题本质仍非线程安全多线程需用并发集合红黑树优化提升冲突时的查询性能记忆口诀JDK8 改尾插解决死循环问题问Java 泛型中的通配符 T、E、K、V、分别是什么含义答T表示任意具体 Java 类型用于泛型类 / 方法定义E表示集合中的元素类型如 ListEK表示键值对中的键类型V 表示值类型表示不确定的任意类型用于方法参数记忆口诀T 类 E 元 K 键 V 值通配问泛型通配符 T 和的核心区别是什么答T 用于定义泛型类 / 方法是确定的类型用于方法参数 / 返回值是不确定的类型T 可进行类型操作不能直接操作类型T 需指定具体类型可代表任意类型记忆口诀T 定义用传参用问什么是上界通配符和下界通配符答上界通配符extends E表示 E 或其子类下界通配符super E表示 E 或其父类上界用于读取下界用于写入配合 PECS 原则提升泛型代码灵活性记忆口诀上界 extends下界 super读上写下问为什么 ArrayList 线程不安全却在开发中被广泛使用答绝大多数场景 List 是线程私有无并发问题无锁开销所有操作性能远高于线程安全集合设计哲学不强制为不需要的功能买单提供快速失败机制便于发现并发问题记忆口诀单线程用 ArrayList性能高无开销问多线程环境下如何正确使用 List答使用 Collections.synchronizedList 包装 ArrayList使用 CopyOnWriteArrayList适合读多写少不推荐使用 Vector性能差已被淘汰复合操作如迭代仍需手动加锁保证安全记忆口诀多线程用并发 List读多写少用 COW问Vector 为什么被淘汰了答所有方法加 synchronized性能开销大复合操作如迭代仍非线程安全需手动加锁被 Collections.synchronizedList 和 COW 替代设计老旧不符合现代集合框架理念记忆口诀Vector 性能差已被并发集合替代问Java 中 List 的常用高效操作有哪些答去重stream.distinct () 一行代码实现删除元素removeIf () 按条件批量删除排序Collections.sort () 或 lambda 表达式排序集合运算stream 实现交并差集和去重并集记忆口诀List 常用操作流一行搞定问List 去重的正确方法有哪些答Java8stream.distinct () 保留插入顺序利用 HashSet 去重性能高但无序双重 for 循环 contains性能差不推荐一行代码即可完成简洁高效记忆口诀流去重保序HashSet 去重快问List 删除元素为什么不能用正序 for答正序删除会导致元素前移出现漏删推荐使用 removeIf ()一行代码安全删除倒序 for 循环删除不会出现索引错位使用 Iterator 迭代器删除避免并发异常记忆口诀正序删漏删倒序迭代最安全

更多文章