news 2026/5/25 21:38:46

大厂 Java 面试实录:严肃面试官 VS 水货程序员谢飞机,3轮连问后“回家等通知”

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
大厂 Java 面试实录:严肃面试官 VS 水货程序员谢飞机,3轮连问后“回家等通知”

大厂 Java 面试实录:严肃面试官 VS 水货程序员谢飞机,3轮连问后“回家等通知”

正文

“下一位,谢飞机。”

会议室门缓缓打开,一位穿着格子衫、背着双肩包、头发略显倔强的程序员探进脑袋。

“您好面试官,我叫谢飞机,五年……额,三年半……呃,反正很多年开发经验,主攻 Java 全栈后端架构调优分布式高并发微服务生态闭环。”

面试官抬了抬眼镜:“坐。简历上写你熟悉 Java 核心、JUC、JVM、SpringCloud、Dubbo、Redis、MySQL、Docker、DDD。那我们开始。”

谢飞机正襟危坐:“您问,我这人最大的优点就是,回答问题的时候特别自信。”

面试官:“希望你的技术和自信成正比。”

谢飞机:“那可能要让您失望一半了。”


第一轮:从基础集合到并发,看看你是不是‘真会写 Java’

问题 1:说一下HashMap的底层数据结构,以及为什么线程不安全?

面试官:“先来个基础题。HashMap底层是什么?”

谢飞机:“这个我会。HashMap底层是数组加链表加红黑树。数据先通过 hash 找桶位,发生冲突就挂链表,如果链表太长就转红黑树,提升查询效率。”

面试官点头:“嗯,继续,为什么线程不安全?”

谢飞机:“因为……多个线程一起 put 的时候,大家都很着急,一个不小心就把数据覆盖了。以前好像还能形成死循环,CPU 原地升天。”

面试官:“回答还行,至少不是背错版本。”

谢飞机嘴角上扬:“谢谢老师,我在集合这块一直比较集合。”


问题 2:ArrayListLinkedList的区别,业务中你怎么选?

面试官:“那ArrayListLinkedList呢?”

谢飞机:“ArrayList底层是动态数组,查询快,随机访问效率高,尾部插入也还行;LinkedList是双向链表,理论上插入删除快。”

面试官:“为什么说理论上?”

谢飞机:“因为如果你先得遍历半天才能找到位置,那也没多快。实际业务里大部分还是用ArrayList,缓存友好,性能通常更稳。”

面试官难得露出一点赞许:“不错,这个回答比很多只会背八股的人强。”

谢飞机小声嘀咕:“我主要是背过很多次,背出感情了。”


问题 3:synchronizedReentrantLock有什么区别?

面试官:“进入并发。synchronizedReentrantLock区别是什么?”

谢飞机:“呃……都是锁。synchronized是 JVM 帮你管,ReentrantLock是 Java 代码自己管。然后ReentrantLock更灵活,可以 tryLock,可以可中断,可以公平锁,还能绑定多个 Condition。”

面试官:“那你平时怎么选?”

谢飞机:“简单同步我就synchronized,代码短,不容易忘记释放锁;复杂并发场景,比如超时获取锁、可中断等待、多条件队列,我就ReentrantLock。”

面试官:“可以。”

谢飞机挺直腰板:“您这句可以,对我很重要。”


问题 4:线程池核心参数有哪些?线上为什么不建议用Executors创建线程池?

面试官:“说说线程池。”

谢飞机:“线程池核心参数有corePoolSizemaximumPoolSizekeepAliveTime、阻塞队列、线程工厂、拒绝策略。”

面试官:“那为什么不建议直接用Executors?”

谢飞机:“因为……它太贴心了,贴心得容易出事。比如有的队列是无界的,任务一多容易把内存撑爆;有的线程数能开到特别大,会把机器打挂。”

面试官:“还算准确。那如果是订单系统异步发通知,你怎么配置线程池?”

谢飞机沉思两秒:“我一般看心情……啊不是,看业务峰值、任务类型、响应时延要求、机器核数来定。CPU 密集型线程数接近 CPU 核数,IO 密集型可以适当高一些。”

面试官:“前半句删掉,后半句还行。”


第二轮:结合业务,从 Spring 到缓存和数据库

面试官翻了翻简历:“你做过电商系统,那我们就按下单链路问。”

谢飞机:“好,我对下单很熟,尤其对没抢到优惠券这件事非常有业务理解。”


问题 1:Spring 中 Bean 的生命周期大致是什么?

面试官:“如果一个订单服务是 Spring Bean,它的生命周期你说一下。”

谢飞机:“这个……先实例化,再属性注入,然后如果实现了一些感知接口就回调,再执行初始化方法,最后就可以被用了。容器关闭时如果配置了销毁方法,还会执行销毁。”

面试官:“那 BeanPostProcessor 在哪?”

谢飞机:“在初始化前后都可以增强 Bean,比如 AOP、代理对象生成很多都和它有关系。”

面试官轻轻点头:“基础还算扎实。”

谢飞机:“谢谢,我在 Bean 生命周期这块,活得也挺完整。”


问题 2:Spring 事务为什么会失效?举个下单场景例子。

面试官:“订单创建、扣库存、写支付流水,Spring 事务在哪些情况下会失效?”

谢飞机:“常见有这些:

  1. 方法不是public
  2. 自调用,自己类里直接调自己的事务方法;
  3. 异常被吃掉了没有抛出;
  4. 数据库引擎不支持事务;
  5. 没有被 Spring 管理;
  6. 配置的回滚异常类型不对,比如默认对运行时异常回滚。”

面试官:“如果订单方法里 try-catch 把异常吞了会怎样?”

谢飞机:“事务管理器以为你成功了,就给你提交了。结果订单写进去了,库存没扣成,数据就不一致。”

面试官:“不错,这题答得挺顺。”

谢飞机开始膨胀:“我在失败经验这块,积累非常丰富。”


问题 3:MyBatis 的#{}${}有什么区别?为什么一般不用${}

面试官:“继续。MyBatis 里参数占位符区别呢?”

谢飞机:“#{}是预编译占位,会转成?,由 PreparedStatement 设置参数,能防 SQL 注入;${}是字符串直接拼接,风险比较大。”

面试官:“那${}完全不能用吗?”

谢飞机:“也不是,比如动态表名、排序字段这类场景可能会用,但必须严格校验,不能让用户随便传。”

面试官:“这个回答没问题。”

谢飞机:“我终于在数据库领域,像个人了。”


问题 4:Redis 缓存穿透、击穿、雪崩分别是什么?电商商品详情怎么设计?

面试官:“商品详情页访问量很高,用 Redis 怎么扛?”

谢飞机:“缓存穿透就是查一个根本不存在的数据,请求每次都打到数据库;击穿是某个热点 key 失效瞬间,大量请求直冲 DB;雪崩是大量 key 同时过期或者 Redis 整体挂了。”

面试官:“那怎么解决?”

谢飞机:“穿透可以缓存空值、布隆过滤器;击穿可以热点 key 永不过期或者互斥锁重建缓存;雪崩可以给过期时间加随机值、做多级缓存、限流降级、Redis 高可用。”

面试官:“如果商品价格经常变化呢?”

谢飞机:“那就……价格单独做 key,或者通过延时双删、旁路缓存更新、订阅变更消息来保证相对一致性。”

面试官:“可以,说明做过一些实际场景。”

谢飞机:“也有可能是事故做多了。”


问题 5:MySQL 索引底层为什么用 B+ 树?

面试官:“最后一个,MySQL 索引为什么常用 B+ 树,不用红黑树或者普通 B 树?”

谢飞机:“因为数据库数据在磁盘上,B+ 树更适合磁盘 IO。它层级低,范围查询也方便,叶子节点还能形成有序链表。”

面试官:“普通 B 树为什么差一些?”

谢飞机:“B 树每个节点都存数据,范围扫描没 B+ 树顺;红黑树树高也容易更高,磁盘访问次数更多。”

面试官:“还可以。”

谢飞机擦了擦额头:“老师,我觉得第二轮我发挥出了带专985的水平。”

面试官:“不要给学历系统制造歧义。”


第三轮:分布式与架构题,开始拉开差距

面试官合上简历:“下面问点复杂的,看看你到底是架构师,还是‘会改配置的 CRUD 工程师’。”

谢飞机咽了口水:“老师您尽量温柔一点,我的分布式知识比较怕生。”


问题 1:Dubbo 一次服务调用大致经过哪些过程?如果超时,你怎么排查?

面试官:“说说 Dubbo 调用链路。”

谢飞机:“消费者启动时会从注册中心拉取提供者地址,做负载均衡,选一个服务节点,然后通过代理发起远程调用,经过序列化、网络传输,到服务端执行,再把结果返回。”

面试官:“如果一个查询订单接口频繁超时呢?”

谢飞机:“先看是不是网络抖动、服务端处理慢、数据库慢 SQL、线程池满了、连接池不够、序列化太重、GC 卡顿……反正哪里都可能慢。”

面试官:“排查步骤呢?”

谢飞机:“呃……先看日志,再看监控,再看机器,再看 JVM,再看数据库,再问同事。”

面试官面无表情:“最后一步倒是很多人都会。”


问题 2:RabbitMQ 如何保证消息不丢?如果重复消费怎么办?

面试官:“下单后要发消息通知库存、积分、物流。RabbitMQ 如何保证消息可靠性?”

谢飞机:“这个问题很大,我尽量组织一下语言。生产者要保证消息发到 MQ,可以用发送确认机制;MQ 本身要做持久化,比如交换机、队列、消息持久化;消费者处理时要手动 ack,处理成功再确认。”

面试官:“如果消费者消费成功了,但 ack 前进程挂了呢?”

谢飞机:“那消息会重新投递,所以业务要保证幂等。比如根据订单号、消息 ID 做去重,或者借助唯一索引、状态机控制避免重复处理。”

面试官:“那消息积压怎么办?”

谢飞机:“扩容消费者,提高并发;检查是不是有慢消息、异常重试风暴;必要时做消息分级处理。”

面试官:“这题答得还算像样。”

谢飞机:“谢谢老师,我在 MQ 这块属于半懂不懂里懂得比较多的。”


问题 3:讲一下 JVM 内存结构、对象创建过程,以及一次 Full GC 可能由什么引起?

面试官:“JVM 来了。说。”

谢飞机眼神开始飘忽:“JVM 内存结构有堆、栈、方法区、程序计数器、本地方法栈。对象一般先在……年轻代里分配,如果放不下可能大对象直接进老年代。对象创建要先类加载检查、分配内存、初始化零值、设置对象头、执行构造方法。”

面试官:“那 Full GC 的常见原因呢?”

谢飞机:“这个……内存不够的时候就会 Full GC。还有 System.gc(),还有那个……元空间满了?老年代满了?反正 GC 不讲武德的时候就会来。”

面试官沉默了两秒:“你这回答,前半段像背过,后半段像许愿。”

谢飞机尴尬一笑:“JVM 比较抽象,我一般和它通过日志沟通。”


问题 4:线程池参数如何根据业务压测结果调优?

面试官:“再来一道多线程和性能相关。线程池调优你怎么做?”

谢飞机:“先区分任务类型,CPU 密集还是 IO 密集。然后看压测 TPS、响应时间、队列堆积、线程活跃数、拒绝次数、CPU 使用率、上下文切换这些指标。”

面试官:“如果线程数一味增加,为什么不一定更快?”

谢飞机:“因为线程太多会带来上下文切换开销、锁竞争、CPU 抢占,还可能把数据库、Redis、下游接口一起压垮。”

面试官:“那你会怎么定?”

谢飞机:“先给一个初始值,压测观察瓶颈,再逐步调 core、max、queue 容量和拒绝策略,找到吞吐和延迟的平衡点。”

面试官:“这题回答还可以。”

谢飞机心里又亮了一盏灯。


问题 5:你理解的 DDD 是什么?如果做一个优惠券系统,如何拆分领域?

面试官:“最后一道。DDD 怎么理解?”

谢飞机:“DDD 就是……领域驱动设计。核心思想是按业务领域建模,不是按数据库表硬拆。会有实体、值对象、聚合、领域服务、应用服务、仓储这些概念。”

面试官:“那优惠券系统呢?”

谢飞机:“可以拆成券模板、券发放、券领取、券核销、规则校验这些领域……大概。然后用聚合根统一管理一致性。再画一堆图,让系统显得很高级。”

面试官:“前半句还行,最后一句很诚实。”

谢飞机:“因为我见过有些项目,业务还没理清,先把包名改成 domain、application、infrastructure 了。”

面试官终于忍不住笑了一下。


面试结束

面试官合上电脑:“今天先到这里。你的基础题回答还可以,部分业务场景也有一定理解;但在 JVM、分布式排障、DDD 落地这些复杂问题上,深度还不够,回答比较发散。”

谢飞机坐得笔直:“老师,我这个人优点就是可塑性强,缺点就是现在还没塑好。”

面试官:“嗯,你先回去等通知吧。”

谢飞机起身,深深鞠躬:“好的老师,希望这个通知不是‘感谢参与’。”

走出会议室后,谢飞机掏出手机记下两句话:

  1. 基础八股还能救命;
  2. JVM 不能再靠玄学了。

面试问题标准答案详解

下面对上面所有问题做系统梳理,帮助小白真正学明白。


1. HashMap 底层数据结构,以及为什么线程不安全

底层结构

JDK 1.8 中,HashMap底层是:

  • 数组(桶)
  • 链表
  • 红黑树

数据插入时:

  1. 先根据 key 的 hash 值计算桶下标;
  2. 如果该桶为空,直接放入;
  3. 如果冲突,先挂到链表;
  4. 当链表长度超过阈值且数组容量达到一定条件后,链表会树化为红黑树。

为什么线程不安全

在多线程下:

  • 多线程 put 可能导致数据覆盖;
  • 扩容 resize 时可能产生数据丢失或结构异常;
  • JDK 1.7 中头插法在并发扩容下可能形成链表死循环;
  • 多线程读写没有加锁,数据可见性和原子性都无法保证。

解决方案

  • 并发场景优先使用ConcurrentHashMap
  • 或者外部加锁控制

2. ArrayList 和 LinkedList 的区别

ArrayList

  • 底层:动态数组
  • 优点:
    • 支持随机访问,get(index)
    • 尾部插入性能较好
    • 内存连续,缓存命中率高
  • 缺点:
    • 中间插入、删除需要移动元素
    • 扩容会有数组拷贝成本

LinkedList

  • 底层:双向链表
  • 优点:
    • 已知节点位置时,插入删除较方便
  • 缺点:
    • 随机访问慢,要遍历
    • 节点额外保存前驱后继指针,内存开销更大
    • CPU 缓存不友好

实际怎么选

绝大多数业务场景优先ArrayList。除非明确需要频繁在链表特定位置插入删除,否则一般不用LinkedList


3. synchronized 和 ReentrantLock 的区别

synchronized

  • Java 内置关键字
  • 使用简单,自动加锁和释放锁
  • 适合简单同步场景
  • 早期性能一般,后来经过偏向锁、轻量级锁等优化后性能不错

ReentrantLock

  • JUC 包中的显示锁
  • 需要手动lock()unlock()
  • 功能更丰富:
    • 支持可中断锁lockInterruptibly()
    • 支持超时获取锁tryLock()
    • 支持公平锁/非公平锁
    • 支持多个条件队列Condition

如何选择

  • 简单同步:优先synchronized
  • 高级并发控制:用ReentrantLock

4. 线程池核心参数,以及为什么不建议用 Executors

ThreadPoolExecutor 核心参数

  1. corePoolSize:核心线程数
  2. maximumPoolSize:最大线程数
  3. keepAliveTime:非核心线程空闲存活时间
  4. workQueue:任务阻塞队列
  5. threadFactory:线程工厂
  6. RejectedExecutionHandler:拒绝策略

任务执行流程

  1. 当前线程数 < core,直接创建核心线程执行
  2. 否则任务进入队列
  3. 队列满了且线程数 < max,再创建非核心线程
  4. 如果线程数达到 max 且队列也满,则触发拒绝策略

为什么不建议用 Executors

Executors某些工厂方法隐藏了风险:

  • newFixedThreadPool():使用无界队列,任务过多可能 OOM
  • newCachedThreadPool():最大线程数接近无限,可能创建过多线程
  • newSingleThreadExecutor():也是无界队列风险

正确做法

直接使用ThreadPoolExecutor,明确指定参数。


5. Spring Bean 生命周期

大致流程:

  1. 实例化 Bean
  2. 属性注入
  3. 执行 Aware 接口回调
  4. BeanPostProcessor前置处理
  5. 执行初始化方法:
    • InitializingBean.afterPropertiesSet()
    • 自定义 init-method
  6. BeanPostProcessor后置处理
  7. Bean 可被使用
  8. 容器关闭时执行销毁方法:
    • DisposableBean.destroy()
    • 自定义 destroy-method

作用

理解生命周期有助于理解:

  • AOP 代理生成
  • Bean 初始化扩展
  • 自定义框架能力实现

6. Spring 事务为什么会失效

常见原因:

  1. 自调用失效:同类内部方法直接调用,绕过代理
  2. 方法不是 public:默认代理可能不生效
  3. 异常被吞掉:事务感知不到异常,导致提交
  4. 抛出的不是配置回滚的异常类型
  5. 对象不是 Spring 容器管理的 Bean
  6. 数据库引擎不支持事务,如 MyISAM
  7. 传播行为使用不当

实战建议

  • 事务方法放到独立 Bean 中
  • 不要吞异常
  • 明确回滚规则rollbackFor = Exception.class

7. MyBatis 的 #{} 和 ${}

#{}

  • 预编译参数占位符
  • 生成 SQL 时用?
  • 自动处理参数类型
  • 可以防止 SQL 注入

${}

  • 字符串直接拼接
  • 不会预编译
  • 存在 SQL 注入风险

什么时候会用 ${}

  • 动态表名
  • 动态排序字段

但必须做白名单校验,绝不能直接接收用户输入拼接。


8. Redis 缓存穿透、击穿、雪崩

缓存穿透

查询不存在的数据,缓存和数据库都没有,每次都打到数据库。

解决:

  • 缓存空对象
  • 布隆过滤器
  • 接口参数校验

缓存击穿

热点 key 在失效瞬间,大量请求同时访问数据库。

解决:

  • 热点数据永不过期
  • 互斥锁/分布式锁重建缓存
  • 后台异步刷新

缓存雪崩

大量 key 同时过期,或 Redis 整体不可用,导致请求大量打到 DB。

解决:

  • 过期时间加随机值
  • Redis 主从、哨兵、集群
  • 多级缓存
  • 限流、降级、熔断

9. MySQL 索引为什么用 B+ 树

原因一:降低磁盘 IO 次数

B+ 树是多叉平衡树,一个节点能放很多 key,树高低,查找时磁盘 IO 更少。

原因二:范围查询更高效

B+ 树的数据都在叶子节点,并且叶子节点之间有链表连接,非常适合范围扫描。

原因三:更稳定

B+ 树非叶子节点只存索引,不存数据,所以每个节点能容纳更多索引项。

为什么不是红黑树

红黑树是二叉树,树高更高,磁盘 IO 更频繁,不适合数据库索引。

为什么不是普通 B 树

B 树的数据分散在各层,不如 B+ 树适合范围查找和顺序扫描。


10. Dubbo 一次调用过程,以及超时排查思路

调用过程

  1. 服务提供者启动并注册到注册中心
  2. 消费者启动,从注册中心订阅服务地址
  3. 消费者通过负载均衡选择一个提供者
  4. 通过动态代理发起远程调用
  5. 请求进行序列化并通过网络发送
  6. 服务端反序列化、执行业务逻辑
  7. 结果返回给客户端

超时排查思路

可以按链路逐层排查:

  1. 客户端:超时时间配置是否合理
  2. 网络层:网络抖动、丢包、连接数是否异常
  3. 服务端线程池:是否满载、队列堆积
  4. 业务逻辑:是否存在耗时计算
  5. 数据库:慢 SQL、锁等待、连接池不足
  6. 缓存/下游依赖:Redis、MQ、第三方接口是否慢
  7. JVM:是否频繁 GC,Stop-The-World 时间过长
  8. 机器资源:CPU、内存、磁盘、负载是否异常

常用手段

  • 查看调用链监控
  • 看服务日志
  • 看线程 dump
  • 看 GC 日志
  • 分析慢 SQL
  • 看 Prometheus/Grafana 等监控

11. RabbitMQ 如何保证消息不丢,以及如何处理重复消费

如何保证消息不丢

从三个阶段看:

1)生产者到 MQ
  • 开启publisher confirm
  • 必要时结合return机制处理路由失败
  • 发送失败要重试或记录补偿
2)MQ 自身存储
  • 队列持久化
  • 交换机持久化
  • 消息持久化
  • 集群/镜像队列提高可用性
3)MQ 到消费者
  • 消费者手动 ack
  • 处理成功后再确认
  • 失败可重试、转死信队列

重复消费怎么处理

因为网络抖动、消费者重启、ack 失败等都可能导致重复投递,所以业务必须做幂等。

幂等方案

  • 唯一消息 ID + 去重表
  • Redis setnx 去重
  • 数据库唯一索引
  • 根据业务状态判断是否已处理

12. JVM 内存结构、对象创建过程、Full GC 原因

JVM 运行时数据区

  1. 程序计数器:记录当前线程执行字节码的位置
  2. 虚拟机栈:方法调用时的栈帧
  3. 本地方法栈:本地方法服务
  4. :存放对象实例,是垃圾回收的主要区域
  5. 方法区/元空间:存放类元数据、常量、静态变量等

对象创建过程

  1. 类加载检查:类是否已加载
  2. 分配内存:在堆上给对象分配空间
  3. 初始化零值:成员变量先赋默认值
  4. 设置对象头:如 hash、GC 分代信息等
  5. 执行<init>构造方法

Full GC 常见触发原因

  • 老年代空间不足
  • 晋升失败
  • 大对象直接进入老年代导致空间紧张
  • System.gc()显式触发
  • 元空间不足
  • CMS/G1 等垃圾收集过程中的特定回收条件触发

如何排查

  • 看 GC 日志
  • 看堆内存分配情况
  • 导出 heap dump 分析对象占用
  • 排查内存泄漏、对象生命周期过长问题

13. 线程池如何调优

调优步骤

  1. 明确业务类型:CPU 密集 / IO 密集
  2. 估算并发量和任务耗时
  3. 通过压测观察指标:
    • TPS
    • RT
    • 活跃线程数
    • 队列长度
    • 拒绝次数
    • CPU 使用率
    • 上下文切换
  4. 调整参数:
    • corePoolSize
    • maximumPoolSize
    • queueCapacity
    • keepAliveTime
    • 拒绝策略
  5. 结合下游承载能力一起看,不能只盯线程池本身

为什么线程越多不一定越快

  • 上下文切换开销变大
  • 锁竞争加剧
  • CPU 被打满
  • 下游数据库/缓存被压垮
  • 内存消耗增大

原则

找到系统吞吐、延迟、资源消耗三者的平衡点。


14. DDD 是什么,优惠券系统如何拆分领域

DDD 核心思想

DDD(领域驱动设计)强调:

  • 软件设计要围绕核心业务领域展开
  • 技术模型要贴近业务语言
  • 通过建模提升复杂业务的可维护性

常见概念

  • 实体 Entity:有唯一标识,如优惠券实例
  • 值对象 Value Object:无唯一标识,如有效期规则
  • 聚合 Aggregate:一组具有一致性边界的对象集合
  • 聚合根 Aggregate Root:聚合对外唯一入口
  • 领域服务 Domain Service:不适合放到实体中的领域逻辑
  • 应用服务 Application Service:负责编排流程
  • 仓储 Repository:负责持久化访问

优惠券系统拆分示例

可以拆成以下子域:

  1. 券模板领域:定义券规则、门槛、折扣方式、有效期
  2. 发券领域:向用户发放优惠券
  3. 领券领域:用户主动领取
  4. 核销领域:下单时校验并使用优惠券
  5. 规则引擎/校验领域:校验是否满足使用条件

为什么这样拆

因为优惠券系统的核心不是“几张表”,而是:

  • 券怎么定义
  • 谁能领
  • 什么时候能用
  • 使用时怎样保证一致性
  • 如何防止超发、重复领取、重复核销

DDD 适合复杂业务,不是简单把包名改成domain就算落地了。


15. 补充:Linux、Docker、设计模式面试常见延伸点

虽然故事里没逐个展开,但真实面试中这些也常问。

Linux 常见问题

  • top:看系统负载
  • ps -ef | grep:查进程
  • netstat -tunlp/ss -lntp:查端口
  • tail -f:实时看日志
  • grepawksed:日志分析
  • df -h:看磁盘空间
  • free -m:看内存

Docker 常见问题

  • 镜像是静态模板,容器是运行实例
  • 常用命令:
    • docker ps
    • docker images
    • docker logs
    • docker exec -it
  • 核心价值:环境一致、快速部署、资源隔离

设计模式常见问题

  • 单例模式:全局唯一实例
  • 工厂模式:封装对象创建
  • 策略模式:多种算法/规则可替换
  • 模板方法模式:定义流程骨架,子类实现差异
  • 代理模式:增强目标对象能力,Spring AOP 常见
  • 责任链模式:请求沿链路逐步处理,如审批流、过滤器

总结

这场面试里,谢飞机给我们上了很生动的一课:

  • 基础题一定要扎实,集合、并发、Spring、缓存、数据库索引都是高频题;
  • 复杂题不能只会背结论,要能结合业务讲原理、讲排查、讲取舍;
  • 分布式系统重点在可靠性、性能、幂等、一致性、可观测性;
  • JVM 和线程池调优是区分初中高级工程师的重要分水岭;
  • DDD不是换目录结构,而是面向复杂业务建模。

如果你也正在准备 Java 面试,不妨把这篇文章里的问题逐个吃透。别让自己在面试现场,像谢飞机一样:基础题满面春风,复杂题开始随风飘零。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/5/25 21:37:15

056子集

子集 题目链接&#xff1a;https://leetcode.cn/problems/subsets/description/?envTypestudy-plan-v2&envIdtop-100-liked 我的解答&#xff1a; public List<List<Integer>> subsets(int[] nums) {List<List<Integer>> ans new ArrayList<&…

作者头像 李华
网站建设 2026/5/25 21:36:44

告别手动测试!VtestStudio结合CAPL脚本实现自动化测试的保姆级教程

从手动到自动化&#xff1a;VtestStudio与CAPL脚本构建车载测试新范式在车载电子系统日益复杂的今天&#xff0c;传统手动测试已难以满足CAN总线等车载网络的高效验证需求。VtestStudio作为Vector公司推出的专业测试平台&#xff0c;结合CAPL脚本语言的强大功能&#xff0c;为工…

作者头像 李华
网站建设 2026/5/25 21:32:24

基于LPC800 MCU的工业定时器改造:从NE555到高精度数字控制

1. 项目概述&#xff1a;从模拟到数字&#xff0c;为老设备注入精准“心跳”手头有个老款的UV曝光设备&#xff0c;用来做电路板或者一些光固化工艺的朋友应该不陌生。这设备什么都好&#xff0c;就是那个控制曝光时间的定时器太“复古”了——用的还是经典的NE555芯片加电位器…

作者头像 李华
网站建设 2026/5/25 21:31:06

BiliRoamingX:彻底解决B站体验限制的完整增强方案

BiliRoamingX&#xff1a;彻底解决B站体验限制的完整增强方案 【免费下载链接】BiliRoamingX-integrations BiliRoamingX integrations and patches powered by ReVanced. 项目地址: https://gitcode.com/gh_mirrors/bi/BiliRoamingX-integrations 你是否曾为B站的内容区…

作者头像 李华
网站建设 2026/5/25 21:29:07

Sweet32漏洞深度解析:3DES-CBC在TLS中的生日攻击与实战禁用指南

1. Sweet32到底是什么&#xff1f;一个被低估了十年的“慢刀子”漏洞很多人看到CVE-2016-2183这个编号&#xff0c;第一反应是“2016年的老漏洞&#xff0c;早该修完了”。我去年在给一家省级政务云做渗透复测时也这么想——直到用Wireshark抓到一段看似正常的HTTPS流量&#x…

作者头像 李华
网站建设 2026/5/25 21:24:59

如何在浏览器中一键解密所有加密音乐文件:Unlock-Music完全指南

如何在浏览器中一键解密所有加密音乐文件&#xff1a;Unlock-Music完全指南 【免费下载链接】unlock-music 在浏览器中解锁加密的音乐文件。原仓库&#xff1a; 1. https://github.com/unlock-music/unlock-music &#xff1b;2. https://git.unlock-music.dev/um/web 项目地…

作者头像 李华