26年Java面试高频题汇总(25道)

《面试题目》

  1. ArrayList 和 LinkedList 的底层实现有什么区别?各自在增删改查操作上时间复杂度如何?为什么很多业务场景下 ArrayList 反而比 LinkedList 更合适?
  2. ConcurrentHashMap 在 JDK 1.7 和 JDK 1.8 中实现方式有什么不同?JDK 1.8 为什么放弃分段锁?put 操作时如何保证线程安全?
  3. String、StringBuilder、StringBuffer 的区别是什么?String 为什么设计成不可变?字符串常量池的作用是什么?

《参考解析》

  1. ArrayList vs LinkedList:ArrayList 底层是动态数组,随机访问 O(1),但插入/删除中间元素需要移动后续元素,平均 O(n);LinkedList 底层是双向链表,插入/删除只需改指针理论上是 O(1),但需要先遍历定位到目标节点,实际也是 O(n)。业务场景中 ArrayList 更常用是因为:现代 CPU 缓存对连续内存(数组)访问更友好(局部性原理),而链表节点分散在堆内存各处,缓存命中率低,加上大多数业务场景以遍历/随机访问为主、少量末尾追加,因此 ArrayList 综合性能通常优于 LinkedList。
  2. ConcurrentHashMap JDK1.7 → 1.8 演进:1.7 用 Segment 分段锁,锁粒度是”段”级别,并发度受限于 Segment 数量;1.8 彻底抛弃 Segment,改为 CAS + synchronized,锁粒度细化到每个桶(链表/红黑树头节点),无冲突时用 CAS 无锁插入,有冲突才对头节点加锁,理论并发度等于数组长度,大幅提升了高并发下的吞吐量。
  3. String 为什么设计成不可变:不可变性保证了 String 作为 HashMap key 时哈希值稳定、可以安全地被多线程共享无需同步、支持字符串常量池复用相同字面量节省内存;字符串常量池则是 JVM 为字符串字面量维护的一块共享区域,相同内容的字符串字面量只会保留一份,new String() 创建的对象则不会进入池中,除非显式调用 intern()