Java十道高频面试题

Java基础与集合

1. HashMap的底层数据结构是什么?(JDK 1.7 vs 1.8)

考察点:数据结构演进、哈希冲突解决、扩容死循环问题。

参考答案

HashMap在JDK 1.7和1.8中有着本质的区别,主要体现在底层结构和扩容机制上:

  1. 底层数据结构

    • JDK 1.7 :采用数组 + 链表 。当发生哈希冲突时,使用链表存储,且采用头插法插入新节点。
    • JDK 1.8 :采用数组 + 链表 + 红黑树
      • 优化:当链表长度大于8且数组长度大于64时,链表会转换为红黑树。
      • 目的:将查询时间复杂度从 O(n)O(n) 降低到 O(log⁡n)O(logn) ,解决了哈希冲突严重时查询效率低的问题。
      • 插入方式 :改为尾插法,保持了元素的顺序。
  2. 扩容机制(核心区别)

    • JDK 1.7(头插法导致的死循环):在多线程环境下扩容时,由于头插法会反转链表顺序,可能导致链表形成环形结构(死循环),导致CPU占用率100%。
    • JDK 1.8(尾插法解决死循环):扩容时保持链表顺序,虽然HashMap在1.8中依然是线程不安全的(存在数据覆盖问题),但彻底解决了死循环的问题。
    • **扩容机制:**默认初始容量为16,负载因子为0.75。当元素个数超过容量 * 负载因子时,触发扩容,容量变为原来的2倍,并进行重新哈希(Rehash)。
  3. 哈希计算

    • JDK 1.8:优化了哈希值的计算方式,减少了哈希碰撞的概率,且在扩容时不需要重新计算hash值,而是通过高位运算判断元素位置,效率更高。
2. ConcurrentHashMap如何保证线程安全?(JDK 1.7 vs 1.8)

考察点:锁粒度进化、分段锁 vs CAS+Synchronized。

参考答案

ConcurrentHashMap(CHM)在JDK 1.7和1.8中采用了完全不同的并发控制策略,核心在于锁粒度的不断细化:

  1. JDK 1.7:分段锁(Segment Lock)

    • 结构 :采用Segment数组 + HashEntry数组。Segment继承自ReentrantLock,相当于一个小的HashMap。
    • 原理:将数据分成一段一段存储,给每一段数据配一把锁(默认16个Segment)。
    • 并发度:默认支持16个线程同时并发写(取决于Segment数量)。
    • 缺点:锁粒度较粗(锁住整个Segment),且Segment数量初始化后不可变,内存开销较大。
  2. JDK 1.8:CAS + synchronized(细粒度锁)

    • 结构 :抛弃了Segment,结构与HashMap 1.8一致,即Node数组 + 链表 + 红黑树
    • 原理
      • 空桶插入 :使用CAS(Compare-And-Swap)操作尝试无锁插入,性能极高。
      • 冲突插入 :当发生哈希冲突时,使用synchronized 锁住当前桶(Bucket)的头节点
    • 并发度:理论上取决于数组长度(默认16,动态扩容),只要哈希不冲突,不同线程可以操作不同的桶,互不干扰。
    • 优势 :锁粒度从"段"细化到了"节点/桶",并发性能大幅提升。同时,读操作(get)完全无锁,依靠volatile保证可见性。
3. 为什么重写equals()必须重写hashCode()?

考察点:Object类规范、哈希集合原理。

参考答案

这是为了保证对象在哈希集合(如HashMap、HashSet)中的正确性。

  • 规范 :Java规定,如果两个对象通过equals()比较返回true,那么它们的hashCode()必须相同。
  • 后果 :如果只重写equals而不重写hashCode,两个逻辑上相等的对象可能会计算出不同的哈希值。在存入HashMap时,它们会被放入不同的桶中,导致无法正确获取或去重,违背了集合的设计原则。

并发编程

4. 线程池的核心参数有哪些?工作流程是怎样的?

考察点:ThreadPoolExecutor、生产环境配置。

参考答案

核心参数有7个,最关键的5个是:

  1. corePoolSize:核心线程数(常驻线程)。
  2. maximumPoolSize:最大线程数。
  3. workQueue:任务阻塞队列。
  4. keepAliveTime:非核心线程的空闲存活时间。
  5. RejectedExecutionHandler:拒绝策略。

工作流程

当提交一个新任务时:

  1. 如果当前线程数 < corePoolSize,创建新核心线程执行。
  2. 如果核心线程已满,任务加入workQueue
  3. 如果队列也满了,且线程数 < maximumPoolSize,创建非核心线程执行。
  4. 如果队列满了且线程数已达最大值,执行RejectedExecutionHandler(默认AbortPolicy抛异常)。
5. synchronized和ReentrantLock的区别?

考察点:锁的实现、功能特性。

参考答案

  • 实现层面synchronized是JVM层面的关键字(内置锁),自动加锁释放;ReentrantLock是JDK API层面的类(java.util.concurrent.locks),需要手动lock()unlock()
  • 功能特性
    • synchronized:操作简单,JDK 1.6后进行了大量优化(偏向锁、轻量级锁),不可中断,非公平锁。
    • ReentrantLock:功能更强大,支持可中断尝试获取锁tryLock)、公平锁 以及多条件变量(Condition)。
  • 选择 :代码简洁性优先选synchronized,需要高级功能(如公平锁、中断)选ReentrantLock
6. ThreadLocal的底层原理及内存泄漏问题?

考察点:线程隔离、弱引用。

参考答案

  • 原理 :每个Thread内部维护了一个ThreadLocalMapThreadLocal作为Key(弱引用),存储的数据作为Value(强引用)。获取数据时,从当前线程的Map中通过ThreadLocal实例取出Value。
  • 内存泄漏
    • 原因ThreadLocalMap中的Key是弱引用,容易被GC回收;但Value是强引用。如果线程复用(如在线程池中),且没有手动移除数据,Key被回收后,Value将无法访问也无法回收,导致内存泄漏。
    • 解决 :使用完ThreadLocal后,务必调用remove()方法清理数据。

JVM与Java新特性

7. JDK 21的虚拟线程(Virtual Threads)是什么?

考察点:2026年面试热点、高并发新方案。

参考答案

虚拟线程是JDK 21引入的重磅特性(Project Loom),是一种轻量级线程

  • 核心:它是用户态线程,由JVM调度,而不是直接映射到操作系统内核线程(OS Thread)。
  • 优势:创建成本极低(内存占用极小),可以轻松创建百万级并发线程。它解决了传统线程"一请求一线程"模型在高并发IO场景下的资源瓶颈。
  • 应用:彻底取代了WebFlux等响应式编程的复杂写法,可以用同步代码写出异步的高性能服务。
8. JVM的垃圾回收算法有哪些?G1收集器的特点?

考察点:内存管理、调优基础。

参考答案

  • 常见算法:标记-清除(碎片化)、复制算法(新生代常用)、标记-整理(老年代常用)。
  • G1收集器
    • 特点:面向服务端,将堆内存划分为多个独立的Region。
    • 优势:可预测的停顿时间模型。它能根据用户设定的停顿时间目标,动态调整回收的Region数量。
    • 适用:适合大内存(6GB+)、多核CPU且对停顿时间有要求的场景。

Spring框架

9. Spring Boot的自动配置原理是什么?

考察点:框架源码、约定优于配置。

参考答案

核心在于@EnableAutoConfiguration注解。

  1. 加载 :通过@Import导入AutoConfigurationImportSelector
  2. 读取 :扫描classpath下的META-INF/spring.factories文件(或新版META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports)。
  3. 筛选 :读取所有候选配置类,并利用@Conditional系列注解(如@ConditionalOnClass@ConditionalOnMissingBean)进行按需加载。
  4. 生效:只有当类路径下存在特定类(如RedisTemplate)且容器中不存在相关Bean时,自动配置才会生效。
10. Spring事务失效的常见场景有哪些?

考察点:AOP代理机制、实战避坑。

参考答案

  • 方法非public:Spring事务只支持public方法。
  • 自调用 :同一个类中,非事务方法调用事务方法(this.method()),绕过了代理对象,导致事务失效。
  • 异常被捕获 :在方法内部try-catch了异常,没有抛出,事务管理器无法感知异常,从而无法回滚。
  • 数据库引擎:数据库表引擎不支持事务(如MySQL的MyISAM)。
  • 异常类型不匹配 :默认只回滚RuntimeExceptionError,如果抛出Checked Exception(如IOException)且未配置rollbackFor,事务不会回滚。
    这10道题覆盖了Java后端开发最核心的知识体系,建议你结合自己的项目经验进行记忆。
相关推荐
Brilliantwxx1 小时前
【算法题】递归树+哈希表+分治异或+双指针
开发语言·c++·笔记·算法
yugi9878381 小时前
经典三维表面重建算法(C语言实现)
c语言·开发语言·算法
Hello:CodeWorld1 小时前
高性能多线程数据采集与持久化方案设计与实现
开发语言·c++
aXin_ya1 小时前
微服务第十一天 MQ相关问题
java·微服务·架构
无限进步_1 小时前
【C++】智能指针族谱:auto_ptr、unique_ptr、shared_ptr
java·开发语言·数据结构·c++·算法
ZC跨境爬虫1 小时前
跟着 MDN 学 HTML day_35:(深入解析 CharacterData 抽象接口)
java·前端·ui·html·edge浏览器·媒体
Brilliantwxx1 小时前
【C++】Stack和Queue(初认识和算法题OJ)
开发语言·c++·笔记·算法
录大大i1 小时前
javaWeb中使用AES256+RSA网络数据加密
java·网络·网络安全