面试现场:谢飞机大战互联网大厂面试官
第一轮:Java基础与集合类
- 面试官:谢飞机,你说说HashMap的底层结构? 谢飞机:嗯……数组+链表,JDK8之后链表太长会变红黑树! 面试官:不错,那扩容机制呢? 谢飞机:两倍扩容,然后rehash……大部分元素待的位置差不多。 面试官:还行。那ArrayList和LinkedList区别? 谢飞机:一个用数组,查得快;一个用链表,增删快! 面试官:可以,基础还行。
第二轮:并发编程与Spring生态
- 面试官:线程池的核心参数有哪些? 谢飞机:核心线程数、最大线程数、空闲时间、任务队列、拒绝策略! 面试官:很好。那ThreadPoolExecutor的执行流程? 谢飞机:先开核心线程,满了就进队列,队列满再开最大线程,最后才拒绝。 面试官:有思路。Spring Bean的作用域有哪些? 谢飞机:singleton、prototype……还有request、session,我写Web时用过! 面试官:还行。那Bean的生命周期? 谢飞机:呃……实例化、填充属性、初始化……销毁?中间好像还有Aware接口…… 面试官:有点模糊,继续努力。
第三轮:分布式与高并发难题
- 面试官:Redis缓存穿透怎么解决? 谢飞机:拿布把缓存遮住,不就穿不透了吗? 面试官:…… 面试官:那你了解布隆过滤器吗? 谢飞机:布……布偶猫?我家养了一只英短。 面试官:MyBatis #{} 和 ${} 区别? 谢飞机:一个防SQL注入,一个直接拼接!我知道这个! 面试官:最后一个问题,DDD的分层架构? 谢飞机:D……三层?Controller、Service、Dao? 面试官:……你回去等通知吧。
参考答案详解
1. HashMap 底层结构与扩容
- JDK8前:数组 + 链表
- JDK8后:数组 + 链表/红黑树(阈值8)
- 扩容:resize() 扩为原容量2倍,重新计算索引位置,避免哈希冲突。
- 红黑树转换条件:链表长度 ≥ 8 且 数组长度 ≥ 64。
2. ArrayList vs LinkedList
- ArrayList:基于动态数组,支持随机访问,查询O(1),增删O(n)
- LinkedList:双向链表,增删O(1),查询O(n)
- 使用场景:频繁查询用ArrayList,频繁增删用LinkedList。
3. 线程池执行流程
- 核心参数:corePoolSize, maxPoolSize, keepAliveTime, workQueue, threadFactory, handler
- 执行顺序:
- 当前线程数 < corePoolSize → 创建新线程
- ≥ corePoolSize → 添加到任务队列
- 队列满且 < maxPoolSize → 创建非核心线程
- 超出maxPoolSize → 触发拒绝策略(AbortPolicy等)
4. Spring Bean 生命周期
- 实例化(Instantiation)
- 属性赋值(Populate properties)
- 初始化前(BeanPostProcessor before)
- 初始化(InitializingBean / init-method)
- 初始化后(BeanPostProcessor after)
- 使用中 → 销毁(DisposableBean / destroy-method)
5. Redis 缓存穿透解决方案
- 定义:查询一个不存在的数据,绕过缓存直击数据库。
- 解决方案:
- 布隆过滤器:判断key是否存在(可能存在误判)
- 缓存空值:对不存在的结果缓存null,并设置短过期时间
- 接口校验:ID合法性、权限控制
6. MyBatis #{} 与 ${}
- #{}:预编译处理,防止SQL注入,生成PreparedStatement占位符
- ${}:字符串替换,直接拼接SQL,存在注入风险,适用于动态表名、排序字段
7. DDD 分层架构
- 四层模型:
- 表现层(Presentation Layer)
- 应用层(Application Layer)
- 领域层(Domain Layer)
- 基础设施层(Infrastructure Layer)
- 核心:领域模型驱动设计,聚合根、实体、值对象、仓储模式