Java 后端面试高频题整理(面试版答案)
最近在准备 Java 后端面试,把一些高频八股题重新整理了一遍。
这篇文章主要偏"面试回答风格",尽量用浅显易懂的方式讲清楚原理,适合:
- Java 初中级后端
- 校招 / 社招面试
- 八股突击复习
- 博客收藏
Integer 和 int 有什么区别?为什么泛型只能用包装类型?
面试版答案
int 是 Java 的基本数据类型,Integer 是 int 的包装类,本质上是一个对象。
相比 int,Integer 的主要优点有几个:
1. Integer 可以为 null
java
Integer a = null;
而 int 不行。
这一点在数据库字段映射、参数传递中非常常见。
2. Integer 可以用于泛型和集合
java
List<Integer> list = new ArrayList<>();
不能写:
java
List<int> list = new ArrayList<>();
因为 Java 泛型底层采用的是"类型擦除"。
泛型编译后会被擦除成 Object 或其上界类型,而 int 不是对象,不能当成 Object 使用。
3. Integer 提供了很多工具方法
比如:
java
Integer.parseInt()
Integer.valueOf()
Integer.compare()
4. 自动装箱和拆箱
java
Integer a = 10; // 自动装箱
int b = a; // 自动拆箱
底层本质:
java
Integer.valueOf(10)
a.intValue()
5. Integer 的缺点
- 占用内存更多
- 存在装箱拆箱开销
- null 自动拆箱可能 NPE
例如:
java
Integer a = null;
int b = a; // NullPointerException
自动装箱和拆箱底层怎么实现?
面试版答案
自动装箱和拆箱本质上是 Java 编译器提供的"语法糖"。
自动装箱
java
Integer a = 10;
编译后:
java
Integer a = Integer.valueOf(10);
自动拆箱
java
int b = a;
编译后:
java
int b = a.intValue();
Integer 缓存池
java
Integer a = 100;
Integer b = 100;
System.out.println(a == b); // true
因为 Integer.valueOf() 默认缓存:
text
-128 ~ 127
范围内的整数对象。
抽象类和接口有什么区别?
面试版答案
接口更偏向于"行为规范",抽象类更偏向于"模板复用"。
1. 继承方式不同
Java:
- 类只能单继承抽象类
- 可以实现多个接口
java
class A extends AbstractA
class B implements X,Y
2. 成员不同
接口:
- 只能定义常量
- Java8 后支持 default 方法
抽象类:
- 可以有成员变量
- 可以有普通方法
- 可以有构造方法
3. 设计目标不同
接口:
- 强调"能做什么"
抽象类:
- 强调"是什么"
4. 什么情况下接口不能替代抽象类?
需要共享状态
java
abstract class Animal{
protected String name;
}
需要模板方法模式
java
abstract class Game{
public final void play(){
init();
start();
end();
}
abstract void init();
}
Java 泛型是什么?解决什么问题?
面试版答案
Java 泛型本质是"参数化类型"。
例如:
java
List<String> list = new ArrayList<>();
这里的 String 就是类型参数。
泛型解决的问题
1. 类型安全
没有泛型:
java
List list = new ArrayList();
list.add("abc");
list.add(123);
容易:
java
ClassCastException
有泛型后:
java
List<String> list = new ArrayList<>();
编译阶段就会检查类型。
2. 消除强转
java
String s = list.get(0);
不需要再:
java
(String)
泛型底层:类型擦除
Java 泛型属于"伪泛型"。
编译后:
java
List<String>
List<Integer>
都会擦除成:
java
List
所以:
java
a.getClass() == b.getClass()
结果为:
java
true
ArrayList 底层数据结构
面试版答案
ArrayList 底层是:
java
Object[]
动态数组。
JDK8 的初始化
java
new ArrayList()
不会立刻创建长度为 10 的数组。
第一次 add 时才初始化容量为 10。
扩容机制
ArrayList 扩容一般为原来的 1.5 倍:
newCapacity = oldCapacity + \frac{oldCapacity}{2}
底层通过:
java
Arrays.copyOf()
复制旧数组。
特点
优点:
- 查询快
- 支持随机访问
缺点:
- 中间插入删除慢
- 扩容有复制开销
@Autowired 和 @Resource 的区别
面试版答案
1. 来源不同
@Autowired
来自 Spring:
java
org.springframework.beans.factory.annotation.Autowired
@Resource
来自 JSR-250:
java
javax.annotation.Resource
2. 默认注入方式不同
@Autowired
默认:
text
byType
按类型注入。
@Resource
默认:
text
byName -> byType
优先按名称。
3. 推荐使用方式
Spring 现在更推荐:
java
构造器注入
例如:
java
@RequiredArgsConstructor
接口慢怎么排查?
面试版答案
一般会从:
text
监控 -> 链路 -> SQL -> JVM -> 代码
逐层排查。
1. 看监控
关注:
- RT
- QPS
- CPU
- 内存
- GC
- 线程池
2. 链路追踪
例如:
- SkyWalking
- Arthas
- Zipkin
定位耗时点。
3. 排查 SQL
重点看:
sql
EXPLAIN
观察:
- 是否走索引
- 是否全表扫描
- 是否回表
- 是否深分页
4. JVM 排查
查看:
- Full GC
- 线程阻塞
- 内存泄漏
MySQL 事务和隔离级别
面试版答案
事务具有 ACID 四大特性。
1. 原子性(Atomicity)
要么全部成功,要么全部失败。
通过:
text
Undo Log
实现。
2. 一致性(Consistency)
事务执行前后,数据必须满足业务规则。
3. 隔离性(Isolation)
事务之间互不影响。
通过:
- MVCC
- 锁机制
共同实现。
4. 持久性(Durability)
事务提交后永久保存。
通过:
text
Redo Log
实现。
MySQL 四种隔离级别
1. 读未提交
可能出现:
text
脏读
2. 读已提交
解决脏读。
但可能:
text
不可重复读
3. 可重复读(MySQL 默认)
解决不可重复读。
4. 串行化
事务串行执行。
并发性能最低。
MySQL 索引怎么优化?
面试版答案
1. 避免索引失效
例如:
sql
where date(create_time)=?
可能导致索引失效。
2. 遵守最左匹配原则
联合索引:
sql
(a,b,c)
尽量从左开始匹配。
3. 使用覆盖索引
避免回表。
4. 使用高区分度字段
例如:
- 用户ID
- 手机号
而不是:
- 性别
- 状态
5. 主键尽量递增
减少页分裂。
MySQL 除了 B+Tree 还有哪些索引?
面试版答案
1. Hash 索引
特点:
- 等值查询快
- 不支持范围查询
2. FullText 全文索引
用于:
text
文章搜索
3. R-Tree 空间索引
用于:
text
GIS 地理数据
4. Bitmap 位图索引
适合:
text
低基数字段
为什么 MySQL 选择 B+Tree?
因为 B+Tree:
- 支持范围查询
- 支持排序
- IO 次数少
- 树高度低
综合性能最好。
总结
Java 后端面试里,很多题并不难。
真正拉开差距的,不是"会不会背",而是:
- 能不能讲清楚原理
- 能不能讲出底层逻辑
- 能不能形成体系
建议准备面试时:
- 不要只背定义
- 要理解为什么这样设计
- 学会从"原理 -> 优缺点 -> 场景"去回答
这样会比单纯背八股更容易通过面试。