一、Java核心基础考点剖析
String、HashMap与集合框架的底层实现
在回顾java面试题2015的真题时,我们发现面试官对基础数据结构的考察依然占据主导地位。特别是String类的不可变性设计、HashMap在JDK1.7与1.8版本中的差异,以及ArrayList与LinkedList的性能对比,是每次面试必问的重灾区。
1.1 String类的不可变性及其优势
String类被final修饰,其内部字符数组也被final修饰,这意味着一旦创建,其内容不可更改。这种设计带来了三大优势:1. 常量池优化;2. 线程安全;3. 支持HashMap等集合的高效存储。
1.2 HashMap底层原理演进
在2015年的面试中,JDK1.7的HashMap是重点。它由数组+链表组成,通过哈希碰撞解决冲突。而JDK1.8引入了红黑树,当链表长度超过阈值(默认为8)且数组长度超过64时,链表转换为红黑树,将查找时间复杂度从O(n)降低到O(log n)。
| 特性 | JDK 1.7 HashMap | JDK 1.8 HashMap |
|---|---|---|
| 数据结构 | 数组 + 链表 | 数组 + 链表 + 红黑树 |
| 哈希冲突解决 | 链表 | 链表转红黑树(长度>8) |
| 扩容时机 | 达到阈值前扩容 | 达到阈值时扩容 |
| 线程安全性 | 非线程安全 | 非线程安全 |
1.3 集合框架的选择
ArrayList基于动态数组实现,支持随机访问,插入删除效率低;LinkedList基于双向链表,插入删除效率高,但随机访问慢。在实际开发中,除非有频繁的头部插入删除操作,否则优先选择ArrayList。
二、JVM内存模型与垃圾回收
OOM排查与GC算法详解
JVM是Java工程师进阶的必经之路。在java面试题2015中,关于内存溢出(OOM)和垃圾回收(GC)算法的问题占据了相当大的比重。理解堆内存划分、GC Roots判定以及常用GC收集器的工作原理,是解决线上故障的关键。
常见垃圾收集算法
- 【标记-清除】:分为标记和清除两个阶段,缺点是可以产生大量内存碎片。
- 【复制算法】:将内存分为两块,每次只用其中一块,垃圾回收时将存活对象复制到另一块。适用于对象存活率低的场景(如新生代)。
- 【标记-整理】:标记后让所有存活对象向一端移动,然后清理边界外的内存。适用于对象存活率高的场景(如老年代)。
Java内存区域划分
JVM内存主要分为线程私有区域和线程共享区域:
- 程序计数器:线程私有,记录当前线程执行的字节码行号。
- Java虚拟机栈:线程私有,描述Java方法执行的内存模型,存储局部变量表、操作数栈等。
- 本地方法栈:线程私有,为Native方法服务。
- Java堆:线程共享,是GC的主要区域,分为新生代和老年代。
- 方法区:线程共享,存储类信息、常量、静态变量等。
常用JVM调优参数
-Xms1g -Xmx1g # 初始堆大小和最大堆大小设为1GB
-XX:NewRatio=2 # 老年代与新生代比例为2:1
-XX:SurvivorRatio=8 # Eden与Survivor比例为8:1
-XX:+UseG1GC # 启用G1垃圾收集器
-XX:+PrintGCDetails # 打印GC详细信息
三、Java并发编程(JUC)
线程池、锁机制与CAS原理
随着多核CPU的普及,并发编程成为Java面试的高频考点。在java面试题2015中,线程池的配置、synchronized与ReentrantLock的区别、以及volatile关键字的内存语义是必问内容。
线程池核心参数
创建线程池需关注7大参数:
- corePoolSize:核心线程数
- maximumPoolSize:最大线程数
- keepAliveTime:空闲线程存活时间
- unit:时间单位
- workQueue:任务队列
- threadFactory:线程工厂
- handler:拒绝策略
锁的演进
从偏向锁→轻量级锁→重量级锁的升级过程,体现了JVM对锁竞争的优化。synchronized是重量级锁,依赖Monitor对象;ReentrantLock基于AQS,支持公平锁和中断响应。
CAS与ABA问题
CAS(Compare And Swap)是乐观锁的基础,包含三个操作数:内存值V、旧的预期值A、要更新的新值B。当且仅当V==A时,更新V=B,否则重试。ABA问题可通过AtomicStampedReference解决。
四、主流框架原理(Spring/MyBatis)
AOP、IOC与动态代理
Spring框架作为Java EE的事实标准,其IOC(控制反转)和AOP(面向切面编程)是面试的核心。2015年,Spring MVC与MyBatis的组合非常流行,理解其工作原理有助于深入掌握企业级开发。
4.1 Spring IOC与AOP
IOC:将对象的创建和依赖关系的管理交给Spring容器,通过DI(依赖注入)实现解耦。核心实现是工厂模式和反射。
AOP:将横切关注点(如日志、事务)与业务逻辑分离。Spring AOP基于动态代理实现:如果目标对象实现了接口,使用JDK动态代理;否则使用CGLIB。
4.2 MyBatis缓存机制
MyBatis提供一级缓存(SqlSession级别,默认开启)和二级缓存(Mapper级别,需手动开启)。一级缓存基于PerpetualCache,使用HashMap实现;二级缓存基于Cache接口,可自定义实现。
| 对比项 | JDK动态代理 | CGLIB动态代理 |
|---|---|---|
| 原理 | 基于接口 | 基于继承 |
| 性能 | 早期较慢,JDK8后优化 | 早期较快,JDK8后差异不大 |
| 限制 | 目标类必须实现接口 | 目标类不能是final类或final方法 |
五、数据库与SQL优化
索引原理、事务隔离与慢查询分析
MySQL作为主流关系型数据库,其索引结构和事务隔离级别是面试的常客。在java面试题2015中,B+树索引的优势、覆盖索引、最左前缀原则以及事务的ACID特性是重点。
5.1 B+树索引优势
MySQL InnoDB引擎默认使用B+树索引。相比B树,B+树所有数据存储在叶子节点,非叶子节点只存储键值,使得树更矮胖,减少IO次数。同时,叶子节点通过双向链表连接,适合范围查询。
5.2 事务隔离级别
- 读未提交(Read Uncommitted):可能发生脏读。
- 读已提交(Read Committed):Oracle默认,解决脏读,可能发生不可重复读。
- 可重复读(Repeatable Read):MySQL默认,解决脏读和不可重复读,通过MVCC和Next-Key Lock解决幻读。
- 串行化(Serializable):最高级别,解决所有问题,但性能最低。
5.3 慢查询优化
使用EXPLAIN分析SQL执行计划,关注type(访问类型)、key(实际使用的索引)、rows(扫描行数)和Extra(额外信息)。避免使用SELECT ,尽量使用覆盖索引。