欢迎访问 kaoacca.cn · 专注技术面试备考 · 常见问题 · 网站地图

Java 面试知识点总结

系统化梳理 Java 开发岗位高频考点,覆盖 JVM、集合、并发、Spring、MySQL、Redis、微服务等核心模块, 结合 BAT/TMD 等一线大厂真实面经,提供可落地的备考策略与代码级深度解析, 助你高效构建知识体系,从容应对技术面试。

Java 核心语法与 JVM 内存模型

基础不牢,地动山摇|掌握语言本质是高薪 Offer 的前提

1.1 Java 基础:封装、继承、多态的本质

📝**封装**:通过 private 成员变量 + getter/setter 实现数据隐藏,配合访问控制符(public/private/protected/default)构建安全边界。

📝**继承**:单继承+多实现接口,避免深度继承层次(≤3层为佳),优先用组合代替继承(“组合优于继承”原则)。

📝**多态**:运行时绑定(dynamic binding),通过方法重写(override)实现,底层依赖虚方法表(vtable)——JVM 在类加载时构建 vtable,方法调用时通过对象头指针查找。

示例:多态的典型陷阱

class Animal {
    void speak() { System.out.println("Animal speaks"); }
}
class Dog extends Animal {
    void speak() { System.out.println("Dog barks"); }
    void fetch() { System.out.println("Dog fetches"); }
}
public class Test {
    public static void main(String[] args) {
        Animal a = new Dog(); // 向上转型
        a.speak();            // 输出:Dog barks ✅(重写)
        // a.fetch();         // ❌ 编译错误:Animal 无 fetch()
    }
}

💡向上转型后只能调用父类声明的方法,这是 Java 类型系统安全性的体现。

1.2 JVM 内存区域与线程模型

📝程序计数器(PC Register):线程私有,记录当前执行的字节码指令地址;唯一无 OOM 区域。

📝Java 虚拟机栈(JVM Stack):线程私有,存储栈帧(局部变量表、操作数栈、动态链接、返回地址);栈深度溢出(StackOverflowError) vs 内存不足(OOM)。

📝本地方法栈(Native Method Stack):服务于 native 方法(如 JNI 调用)。

📝堆(Heap):线程共享,存储对象实例;新生代(Eden+S0+S1)与老年代比例默认 1:2;GC 分代依据是“对象生命周期”。

📝方法区(Method Area):JDK8 后为元空间(Metaspace),存储类元数据;不再受限于 JVM 内存,使用本地内存。

区域 是否线程共享 OOM 风险 典型异常
程序计数器 否 无 无
虚拟机栈 否 高(栈深) StackOverflowError
本地方法栈 否 中 OutOfMemoryError
堆 是 高 java.lang.OutOfMemoryError: Java heap space
元空间 是 低(本地内存耗尽) java.lang.OutOfMemoryError: Metaspace

1.3 垃圾回收(GC)机制

📝判断对象存活:
• 引用计数法(Java 不采用,因循环引用问题)
• 可达性分析(根对象:GC Roots → 对象引用链断开 → 可回收)

📝GC Roots 包括:
• 虚拟机栈中引用的对象
• 类静态属性引用的对象
• 常量引用的对象
• 本地方法栈中 JNI 引用的对象

📝GC 算法:
• 标记-清除(产生碎片)
• 标记-复制(新生代,需分半内存)
• 标记-整理(老年代,避免碎片)
• 分代收集(主流方案:新生代用复制 + 老年代用标记整理)

📝垃圾收集器对比:
Serial:单线程,Client 模式默认;
ParNew:Serial 多线程版,配合 CMS;
Parallel Scavenge:高吞吐量,自适应调节策略;
CMS:低停顿,但内存碎片多;
G1:Region 分区 + 可预测停顿(JDK9 默认)。

1.4 类加载机制与双亲委派模型

📝加载过程:
① 加载(Load):将 class 文件二进制流读入内存 → 生成 Class 对象
② 验证(Verify):文件格式、元数据、字节码、符号引用验证
③ 准备(Prepare):为静态变量分配内存并设置默认值(如 int→0)
④ 解析(Resolve):将常量池符号引用转为直接引用
⑤ 初始化(Initialize):执行 () 方法(静态变量赋值 + static 块)

📝双亲委派模型:
双亲委派模型示意图 💡自定义类加载器需重写 loadClass(),但必须先委托父加载器,否则破坏安全模型。

集合框架(Collection & Map)

高频考点:ArrayList vs LinkedList、HashMap 源码、ConcurrentHashMap 原理

ArrayList vs LinkedList vs Vector

特性 ArrayList LinkedList Vector
底层结构 动态数组 双向链表 动态数组(线程安全)
随机访问 ✅ O(1) ❌ O(n) ✅ O(1)
插入/删除 ❌ O(n)(需移动) ✅ O(1)(定位后) ❌ O(n)
线程安全 ❌ ❌ ✅(synchronized 方法)
扩容机制 1.5 倍(JDK8+) 不扩容 2 倍

💡实际开发中,ArrayList 占 90% 以上场景;LinkedList 仅用于频繁头尾插入/删除(如队列实现)。

HashMap 源码深度解析

📝JDK7:数组 + 链表(哈希冲突 → 链地址法)
📝JDK8:数组 + 链表 + 红黑树(链表长度 ≥8 且数组长度 ≥64 → 转红黑树;避免哈希退化)

📝关键参数:
• 初始容量:16(2 的幂)
• 负载因子:0.75(时间与空间平衡点)
• 树化阈值:8
• 链表恢复阈值:6(避免频繁树化/退化)

哈希碰撞攻击示例

// 故意构造哈希冲突的 key,导致 HashMap 性能退化为 O(n)
Map map = new HashMap<>();
for (int i = 0; i < 10000; i++) {
    map.put("a" + (i % 16), "value" + i); // 仅 16 个 key,碰撞严重
}

💡生产环境应避免固定模式的 key,或改用 ConcurrentHashMap。

📝ConcurrentHashMap(JDK8):
• 取消 Segment 分段锁,改用 CAS + synchronized
• Node 数组 + 链表/红黑树
• 线程安全操作:put/get/remove
• size 计算:baseCount + counterCells(避免全量统计)

Set 实现类对比

  • HashSet:基于 HashMap,元素唯一(依赖 hashCode + equals)
  • LinkedHashSet:维护插入顺序(HashMap + 双向链表)
  • TreeSet:基于 TreeMap(红黑树),自然排序或定制比较器

💡TreeSet 使用场景:需排序/范围查询(如成绩排名、时间区间统计)

并发编程(线程与锁)

核心考点:synchronized、volatile、CAS、线程池、JUC 工具类

线程状态与生命周期

JVM 规范定义 6 种状态

NEW → RUNNABLE(start())→ BLOCKED(等待锁)→ WAITING/TIMED_WAITING(wait/sleep/join)→ TERMINATED(run() 结束)

💡BLOCKED 是线程在等待 synchronized 锁;WAITING 是主动等待通知(如 wait())。

volatile 关键字

可见性与禁止指令重排序

• 可见性:线程修改后立即写回主内存,其他线程读取时强制从主内存加载
• 禁止重排序:通过内存屏障(LoadLoad / StoreStore)实现
• 不保证原子性:如 i++ 仍需加锁

💡典型应用:单例模式的双重检查锁(DCL)

CAS 与原子类

Compare-And-Swap,无锁并发

• 底层:CPU 原子指令(lock cmpxchg)
• 问题:ABA 问题(用版本号解决 → AtomicStampedReference)
• 常用类:AtomicInteger、LongAdder(高并发下性能更优)

// LongAdder 高并发计数示例
LongAdder counter = new LongAdder();
executor.submit(() -> {
    for (int i = 0; i < 100000; i++) {
        counter.increment();
    }
});

线程池(ThreadPoolExecutor)参数详解

参数 含义 推荐值
corePoolSize 核心线程数 CPU 核心数 + 1(CPU 密集型)
或 2×CPU 核心数(IO 密集型)
maximumPoolSize 最大线程数 根据任务特性调整
keepAliveTime 非核心线程存活时间 60s(默认)
workQueue 任务队列 SynchronousQueue(直接提交)
LinkedBlockingQueue(无界,慎用)
ArrayBlockingQueue(有界,推荐)
rejectedExecutionHandler 拒绝策略 AbortPolicy(抛异常)
CallerRunsPolicy(调用者线程执行)

💡避免使用 Executors 工厂方法创建线程池(隐藏队列容量问题),应手动构造 ThreadPoolExecutor。

Spring 全家桶(IoC / AOP / 事务)

高频考点:Bean 生命周期、循环依赖、事务传播机制

4.1 Spring IoC 容器与 Bean 生命周期

① 实例化(Instantiation)

通过反射或 CGLIB 创建 Bean 对象(此时属性未赋值)

② 属性赋值(Populate)

依赖注入(DI):@Autowired、@Value、set 方法

③ 初始化(Initialization)

执行 BeanPostProcessor.postProcessBeforeInitialization()
→ InitializingBean.afterPropertiesSet()
→ 自定义 init-method
→ BeanPostProcessor.postProcessAfterInitialization()

④ 使用(Ready)

Bean 已就绪,可被调用

⑤ 销毁(Destruction)

DisposableBean.destroy() + 自定义 destroy-method

📝循环依赖:
• 构造器注入 → 无法解决(抛异常)
• setter 注入 → 三级缓存(singletonObjects / earlySingletonObjects / singletonFactories)

4.2 AOP 原理与代理模式

📝JDK 动态代理:基于接口,生成代理类实现相同接口
📝CGLIB 代理:基于继承,生成子类重写方法(final 方法无法代理)

📝通知类型:
• @Before:前置通知
• @After:最终通知
• @AfterReturning:返回通知
• @AfterThrowing:异常通知
• @Around:环绕通知(最强大)

// 示例:日志切面
@Aspect
@Component
public class LogAspect {
    @Around("execution(* com..service.*.*(..))")
    public Object logExecutionTime(ProceedingJoinPoint joinPoint) throws Throwable {
        long start = System.currentTimeMillis();
        Object result = joinPoint.proceed();
        long time = System.currentTimeMillis() - start;
        System.out.println("Method " + joinPoint.getSignature() + " took " + time + "ms");
        return result;
    }
}

4.3 Spring 事务传播机制

传播行为 说明 示例场景
REQUIRED 有事务则加入,否则新建 默认值,90% 场景
REQUIRES_NEW 挂起当前事务,新建事务 日志记录(独立事务)
NESTED 在当前事务中创建保存点 部分失败可回滚子事务
NOT_SUPPORTED 挂起当前事务,以非事务方式执行 查询缓存(避免事务开销)

💡事务失效常见原因:
• 方法非 public
• 同类中方法调用(绕过代理)
• 异常被 catch 捕获未重新抛出
• 数据库引擎不支持事务(如 MyISAM)

数据库(MySQL)与缓存(Redis)

核心考点:索引原理、事务隔离级别、缓存穿透/击穿/雪崩

5.1 MySQL 索引原理

📝B+ 树结构:
• 只有叶子节点存储数据(非叶子节点仅存索引)
• 叶子节点间有指针连接(范围查询高效)
• 磁盘预读(页大小 16KB)

📝最左前缀原则:
索引 (a,b,c) 可匹配:
• a、a+b、a+b+c
• 但不能单独匹配 b 或 c

📝覆盖索引:查询字段全部在索引中,避免回表

索引失效场景

  • 使用函数或表达式:WHERE YEAR(create_time)=2023
  • 隐式类型转换:WHERE phone='13800138000'(phone 为 int)
  • LIKE 以 % 开头:WHERE name LIKE '%java%'
  • OR 条件未全走索引

5.2 Redis 缓存问题与解决方案

缓存穿透

问题:请求不存在的数据 → 缓存未命中 → 查询数据库 → 未命中 → 缓存不写入 → 大量请求压垮 DB

解决方案:
• 布隆过滤器(BloomFilter)拦截非法 key
• 缓存空对象(设置短 TTL,如 5min)
• 参数校验(防恶意请求)

缓存击穿

问题:热点 key 过期瞬间 → 大量请求同时打到 DB

解决方案:
• 逻辑过期(异步刷新)
• 分布式锁(仅一个线程查询 DB)
• 永不过期 + 定时刷新

缓存雪崩

问题:大量 key 同时过期 → DB 瞬间压力骤增

解决方案:
• 过期时间加随机值(如 3600±600s)
• 热点数据永不过期
• 限流降级(Sentinel)

分布式系统与微服务

高阶考点:CAP 理论、分布式 ID、服务治理、分布式事务

6.1 分布式 ID 生成方案

方案 优点 缺点 适用场景
UUID 简单、全局唯一 无序、长度长、存储浪费 日志、非核心业务
数据库自增 有序、简单 单点瓶颈、分库分表困难 单库小系统
Snowflake 高性能、有序、分布式 依赖时间、时钟回拨问题 主流方案(如百度 UIDGenerator)
Redis INCR 高性能、有序 依赖 Redis 可用性 高并发写入场景

6.2 分布式事务解决方案

① 2PC(两阶段提交)

协调者询问参与者是否可提交 → 全部同意则提交 → 强一致性,但单点故障风险高

② 3PC(三阶段提交)

增加 CanCommit 阶段 + 超时机制 → 降低阻塞,但一致性减弱

③ TCC(Try-Confirm-Cancel)

业务侵入式:Try(预留资源)、Confirm(确认)、Cancel(回滚)
• 优点:高性能
• 缺点:开发复杂(需实现回滚逻辑)

④ Seata(AT 模式)

无侵入:基于本地事务 + 全局协调器
• RM(资源管理器):分支事务
• TM(事务管理器):全局事务
• TC(事务协调器):状态存储

6.3 CAP 理论与 BASE 理论

📝CAP 定理:
一致性(C):所有节点数据一致
可用性(A):每个请求都能响应
分区容错性(P):网络故障下系统仍可用
分布式系统只能同时满足其中两点

📝BASE 理论( compromise 方案):
• Basically Available:基本可用
• Soft State:允许状态延迟
• Eventually Consistent:最终一致

💡电商系统:高可用 + 最终一致(如订单状态同步)

真实企业面试题汇编

来自 BAT/TMD 等一线大厂最新面试反馈|附解题思路与评分标准

7.1 字节跳动:HashMap 红黑树转换条件

问题:为什么链表长度 ≥8 且数组长度 ≥64 才转红黑树?

参考答案:
• 红黑树节点占用空间是链表节点的 2 倍(含左右子节点 + 颜色位)
• 当链表长度 <8 时,链表查询 O(n) 与红黑树 O(log n) 性能差距不大,且链表更省空间
• 阈值 64 是避免小数组频繁树化(数组扩容成本低)
• 面试官评价:✅ 考察源码深度 + 性能权衡思维(9/10 分)

7.2 阿里巴巴:分布式锁实现与 Redis RedLock

问题:RedLock 为何不推荐?如何实现高可用分布式锁?

参考答案:
• RedLock 问题:
- 多节点网络延迟导致锁失效
- 客户端故障时锁未释放
• 推荐方案:
- 单 Redis 实例 + Lua 脚本(原子性)
- Redisson 的 Watchdog 机制(自动续期)
- Zookeeper/Etcd 实现更可靠(强一致性)

面试官评价:✅ 有生产经验 + 技术选型能力(10/10 分)

7.3 腾讯:Spring Boot 自动配置原理

问题:@EnableAutoConfiguration 如何工作?如何排除不需要的自动配置?

参考答案:
• 原理:
1. @Import(AutoConfigurationImportSelector.class)
2. 读取 classpath:/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
3. 按 @Conditional 注解过滤(如 @ConditionalOnClass)
• 排除方式:
@EnableAutoConfiguration(exclude = {DataSourceAutoConfiguration.class})
或在 application.yml:
spring.autoconfigure.exclude: org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration

网友们还关心

高频搜索问题深度解答|覆盖新人入门到进阶

网站地图

快速导航至核心内容模块

斌知网
蜀ICP备2026017620号-5