一年 Java面试 通关指南
从“Hello World”到企业级应用,第一年往往是开发者技术观重塑的关键期。 本页面专为拥有0-2年经验的Java工程师打造,深度解析面试官眼中的“潜力股”标准。
Java 核心基础:拒绝死记硬背
工作一年的开发者,面试官不再关注语法细节,而是关注你对JVM、集合及并发编程的理解深度。
HashMap 底层原理
在一年Java面试中,HashMap是必考题。你需要清楚JDK1.7与1.8的区别: 1.7使用数组+链表,1.8引入了红黑树(链表长度>8且数组长度>64时转换)。 2. 必须掌握hash算法、扩容机制(2倍扩容)以及线程不安全的原因(死链问题在1.7中)。
ConcurrentHashMap 实现
为什么用它?因为线程安全且高效。1.7使用分段锁(Segment),1.8使用CAS+synchronized。 重点理解synchronized只锁定当前链表或红黑树的头节点,大大降低了锁竞争。
ArrayList vs LinkedList
绝大多数场景选ArrayList。LinkedList虽然增删快,但内存开销大(节点对象),且缓存命中率低。 除非有极高频的头部/尾部插入删除,否则不建议使用LinkedList。
内存区域划分
堆(Heap):存放对象实例,是GC的主要区域。 方法区(Method Area):JDK8后变为元空间(Metaspace),存放类信息、常量、静态变量。 虚拟机栈(VM Stack):存放栈帧,与方法调用相关,异常常发生在此(StackOverflowError)。
GC 垃圾回收算法
标记-清除、标记-复制、标记-整理。 新生代通常采用复制算法(Eden:Survivor = 8:1:1),老年代采用标记-整理或标记-清除。 了解G1、ZGC等新型收集器的特点。
类加载机制
加载→验证→准备→解析→初始化→使用→卸载。 双亲委派模型:防止核心API被篡改。打破双亲委派的场景:JDBC驱动加载等。
线程池七大参数
corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, threadFactory, handler。 面试常问:核心线程满了怎么办?队列满了怎么办?最大线程满了怎么办? 拒绝策略:AbortPolicy, CallerRunsPolicy等。
volatile 关键字
保证可见性,不保证原子性,禁止指令重排。 理解Happens-Before原则。与synchronized的区别:轻量级同步,不阻塞线程。
synchronized 原理
偏向锁→轻量级锁(自旋)→重量级锁。 锁升级过程是面试高频点。理解Monitor对象与Object Header的关系。
Spring Boot 与 主流中间件
Spring Boot 自动装配
核心注解:@SpringBootApplication 包含 @EnableAutoConfiguration。
原理:通过 spring.factories (或新版 org.springframework.boot.autoconfigure.AutoConfiguration.imports) 加载配置类。
面试点:如何自定义 starter?如何排除特定自动配置?
AOP 面向切面编程
应用场景:日志记录、事务管理、权限校验。
底层实现:JDK动态代理(基于接口) vs CGLIB(基于继承)。
Spring Boot 2.x 默认使用 CGLIB,可通过 spring.aop.proxy-target-class=true 控制。
Redis 核心数据结构
String, List, Set, ZSet, Hash。 应用场景:缓存(穿透/击穿/雪崩解决方案)、计数器、分布式锁(Redlock)、排行榜。 持久化:RDB(快照)与 AOF(日志)的区别与选择。
MySQL 索引优化
B+树结构优势:叶子节点链表连接,适合范围查询。 最左前缀原则:联合索引 (a,b,c),查询条件必须包含a。 覆盖索引:避免回表。 索引失效场景:函数计算、类型转换、模糊查询左通配。
高频面试题深度解析
| 问题类别 | 典型面试题 | 深度解析要点 |
|---|---|---|
| Spring | Spring Bean 的生命周期是怎样的? |
1. 实例化 (Instantiation) 2. 属性赋值 (Populate) 3. 初始化 (Initialization): BeanPostProcessor前置/后置处理, init-method 4. 销毁 (Destruction) |
| MySQL | 一条 SQL 查询语句的执行流程? | 连接器 → 查询缓存(8.0已移除) → 分析器 → 优化器 → 执行器 → 存储引擎(InnoDB) → 返回结果 |
| Redis | 如何保证缓存与数据库双写一致性? |
1. 先删缓存,再更新数据库,延迟双删 2. 使用 Canal 订阅 binlog 异步更新缓存 3. 设置过期时间,允许短暂不一致 |
| 并发 | ThreadLocal 内存泄漏问题? | Key是弱引用,Value是强引用。GC时Key被回收,但Value还在。 解决:每次使用完后必须调用 remove() 方法。 |
| 设计 | 单例模式有几种写法?哪种最好? |
饿汉式、懒汉式(双重检查锁)、静态内部类、枚举。 推荐:枚举(防反射/序列化攻击) 或 静态内部类(延迟加载且线程安全)。 |
职业发展:从初级到中级
第 1 阶段:夯实基础 (0-6个月)
目标:熟练掌握Java SE,能独立使用Spring Boot开发CRUD功能。
重点:集合源码、MySQL基本SQL优化、Spring IOC/AOP理解。
薪资预期:二三线 6-10k,一线 10-15k。
第 2 阶段:拓展广度 (6-12个月)
目标:引入中间件,解决高并发下的基本问题。
重点:Redis缓存策略、RabbitMQ/Kafka消息队列、Linux部署、Docker基础。
薪资预期:二三线 10-15k,一线 15-25k。
第 3 阶段:深入原理 (12个月+)
目标:理解底层原理,具备系统设计与调优能力。
重点:JVM调优、MySQL分库分表、微服务(Spring Cloud)、分布式事务。
薪资预期:二三线 15-25k,一线 20-35k+。
实战:线程池规范创建示例
在实际开发中,严禁使用 Executors 创建线程池,必须手动创建 ThreadPoolExecutor 以明确参数。
// 推荐写法:手动创建线程池
public class ThreadPoolExample {
public static void main(String[] args) {
ThreadPoolExecutor executor = new ThreadPoolExecutor(
5, // 核心线程数
10, // 最大线程数
60L, // 空闲线程存活时间
TimeUnit.SECONDS, // 时间单位
new ArrayBlockingQueue<>(100), // 工作队列
Executors.defaultThreadFactory(), // 线程工厂
new ThreadPoolExecutor.DiscardPolicy() // 拒绝策略
);
executor.execute(() -> {
System.out.println("Task executed by: " + Thread.currentThread().getName());
});
// 注意:应用关闭时需正确关闭线程池
// executor.shutdown();
}
}