本文写于 2019 年 12 月——经济下行期,面试软技能 + 智力题权重上升。
一、面试软技能清单
1.1 沟通能力
- STAR 法则:Situation(情境)/ Task(任务)/ Action(行动)/ Result(结果)
- 用数据说话:不说"做了高并发系统",说"支持 10 万 QPS、可用性 99.99%"
- 结论先行:先说结论,再说过程
- 听不懂就问:面试官也欣赏"敢问"的人
1.2 抗压能力
- 接受挑战:不回避难题
- 承认边界:不会就说不会,但说明学习路径
- 情绪稳定:不与面试官争论
1.3 学习能力
- 学习路径:展示如何学一项新技术
- 举一反三:用类比说明理解深度
- 总结输出:博客 / GitHub / 技术分享
1.4 团队协作
- 冲突处理:如何处理技术分歧
- 代码评审:如何给别人 review
- 知识传递:如何给团队培训
二、智力题分类
2.1 推理题
经典题:
蓝眼岛:岛上有蓝眼/棕眼两种人,每天傍晚有人离岛。岛主说"你们中间有蓝眼的人",第二天所有蓝眼都离岛了,为什么?
- 解法:n=1 时自己会走(如果自己是棕眼,岛主的话无意义),所以当 n 个人时,递归 n-1 后第 n 步自己走
疯狗:村里有 50 条狗,其中若干是疯狗(不表现出任何症状),每天傍晚杀掉所有疯狗。村民不知道自己是疯狗。第几天杀完?
- 解法:第 49 天(如果有 1 条疯狗,当天就杀光;以此类推)
耳光:100 个逻辑学家围成一圈,每人头上一个数(红/蓝),能看见其他人看不见自己。每晚有人按规则打耳光。三天后耳光声响了,怎么推理?
- 解法:递归 + 公共知识
2.2 二进制问题
经典题:
毒酒问题:1000 桶酒,1 桶有毒,10 只小白鼠,24 小时找出毒酒。
- 解法:每桶编号二进制,每只老鼠喝对应位为 1 的酒。24h 后看哪几只死,二进制转十进制就是毒酒编号
砝码问题:1-100 找最重 / 最轻的多少次?
- 解法:天平分组(3 进制)
- 找最重:1 次分 3 组
- 找最重 + 最轻:⌈n/3⌉ 次
- 解法:天平分组(3 进制)
2.3 先手必胜
经典题:
取石子:100 个石子,每次取 1-3 个,先取必胜?
- 解法:必胜点为 4 的倍数(先手凑到 4 的倍数必胜)
翻硬币:N 枚硬币排成一行,每次翻一枚 + 邻接一枚,所有正面朝上为赢。
- 解法:分奇偶讨论
2.4 水桶问题
经典题:
3 升和 5 升:如何量出 4 升?
- 解法:3L 倒满 5L → 5L 倒掉 → 3L 倒进 5L → 再取 3L 倒满 → 5L 已有 3L 只能再装 2L → 3L 剩 1L → 5L 倒空 → 1L 倒入 5L → 再取 3L → 4L 搞定
8 升和 5 升:量出任意整数升
2.5 赛马问题
经典题:25 匹马,每次只能 5 匹比赛,最少几次找出最快的 3 匹?
解法:
- 6 次(无计时器)/ 5 次(有计时器)
| |
2.6 过河/过桥
经典题:4 人过桥,1/2/5/10 分钟,最少几分钟?
解法:
- 1+2 过,1 回 → 3 分钟
- 5+10 过,2 回 → 12 分钟
- 1+2 过 → 2 分钟
- 总计 17 分钟
2.7 灯泡开关
经典题:3 个开关控制 3 个灯泡(楼下看不见楼上),只能上楼 1 次,怎么确定对应关系?
解法:
- 开 1 号 5 分钟 → 关 1 号 → 开 2 号 → 上楼
- 亮的是 2 号控制
- 灭但热的是 1 号控制
- 灭且冷的是 3 号控制
2.8 最优解问题
经典题:
撕书问题:N 页书(双面),最少多少次撕出 100 张单页?
- 解法:50 张 = 1 次(N/2 张)
煎饼排序:每次翻转前缀,最少几次排好序?
三、Java 集合类
3.1 Java 基础合集
| 类 | 作用 | 关键 |
|---|---|---|
| ArrayList | 动态数组 | 扩容 1.5x |
| LinkedList | 双向链表 | 增删快,查找慢 |
| HashMap | 哈希表 | JDK 8 红黑树化 |
| ConcurrentHashMap | 线程安全哈希表 | CAS + synchronized |
| TreeMap | 红黑树 | 有序 |
| HashSet | 基于 HashMap | O(1) 查找 |
3.2 经典面试追问
Q1:HashMap 为什么用红黑树而不是 AVL?
- AVL 严格平衡,查询快 O(log n)
- 红黑树近似平衡,插入删除快(旋转少)
- 哈希冲突链表 > 8 时转红黑树,避免 hash 攻击退化为 O(n)
Q2:ConcurrentHashMap 1.7 vs 1.8?
- 1.7:Segment(16 个)+ ReentrantLock
- 1.8:Node + CAS + synchronized(锁粒度更细)
Q3:ArrayList vs LinkedList?
| 维度 | ArrayList | LinkedList |
|---|---|---|
| 随机访问 | O(1) | O(n) |
| 头部插入 | O(n) | O(1) |
| 内存占用 | 少 | 多(每个节点 2 个指针) |
| 缓存友好 | 友好 | 不友好 |
四、Java IO 模型
4.1 BIO / NIO / AIO
| 模型 | 全称 | 适用 |
|---|---|---|
| BIO | Blocking I/O | 传统阻塞(连接数少) |
| NIO | Non-blocking I/O | 高并发(Netty 底层) |
| AIO | Asynchronous I/O | 异步回调(Linux 5+) |
4.2 NIO 三大组件
| 组件 | 作用 |
|---|---|
| Channel(通道) | 双向数据通道(FileChannel / SocketChannel) |
| Buffer(缓冲区) | 数据容器(ByteBuffer / CharBuffer) |
| Selector(选择器) | 多路复用(一个线程管理多个 Channel) |
五、MyBatis 实战
5.1 一级缓存 vs 二级缓存
| 维度 | 一级缓存 | 二级缓存 |
|---|---|---|
| 范围 | SqlSession | Mapper(namespace) |
| 默认开启 | ✓ | ✗(需配置) |
| 失效 | 增删改 / commit / close | 同 namespace 增删改 |
5.2 #{} vs $
#{}:预编译,?占位符(防 SQL 注入)${}:字符串拼接(有注入风险)
六、设计模式高频题
6.1 单例模式 8 种实现
| 方式 | 线程安全 | 性能 | 推荐 |
|---|---|---|---|
| 饿汉 | ✓ | 高 | ★★★ |
| 懒汉(同步方法) | ✓ | 低 | ✗ |
| 懒汉(DCL) | ✓ | 中 | ★★★★ |
| 静态内部类 | ✓ | 高 | ★★★★★ |
| 枚举 | ✓ | 高 | ★★★★★ |
| 容器式 | 取决于实现 | - | 单例池 |
| ThreadLocal | 单线程 | 高 | 线程内单例 |
| CAS | ✓ | 高 | ✗(代码复杂) |
6.2 工厂模式 vs 抽象工厂
| 维度 | 工厂方法 | 抽象工厂 |
|---|---|---|
| 复杂度 | 单一产品 | 产品族 |
| 扩展 | 新增产品加新工厂 | 新增产品族加新工厂 |
6.3 代理模式
- 静态代理:手动写代理类
- JDK 动态代理:基于接口(Proxy + InvocationHandler)
- CGLIB 动态代理:基于继承(Enhancer + MethodInterceptor)
七、Netty 面试
7.1 Netty 三大特点
- 异步 NIO:基于 Java NIO
- 事件驱动:ChannelPipeline + ChannelHandler
- 高性能:零拷贝、内存池、无锁设计
7.2 经典面试题
Q1:Netty 的线程模型?
- Reactor 单线程:所有 I/O + 业务在单线程(NIO)
- Reactor 多线程:I/O 单线程 + 业务线程池
- 主从 Reactor 多线程:Main Reactor + Sub Reactor + 业务线程池(Netty 推荐)
Q2:Netty 的零拷贝?
- 堆外内存(DirectByteBuffer)
- CompositeByteBuf(合并多个 buffer)
- FileChannel.transferTo(sendfile 系统调用)
- ByteBuf 池化(减少 GC)
Q3:Netty 的心跳机制?
- IdleStateHandler:读 / 写 / 读写空闲检测
- 服务端定期发送 Ping + 客户端响应 Pong
- 超时未响应则关闭连接
八、写在最后
面试软技能要点:
- STAR 法则:讲故事用情境-任务-行动-结果
- 数据量化:用具体数字说明成就
- 诚实谦逊:不懂就说不懂,承认边界
- 反向提问:准备 2-3 个有深度的问题
