📌 引言:为什么你“会的都考,考的都不会”?

你是否经历过这样的面试场景?

❓ “HashMap 的底层结构是什么?如何解决哈希冲突?”
❓ “线程池的核心参数有哪些?拒绝策略如何选择?”
❓ “JVM 内存模型是怎样的?GC 是如何触发的?”
❓ “volatile 关键字的作用是什么?它能保证原子性吗?”

这些问题看似基础,却往往是决定你能否进入大厂、拿下高薪 Offer 的“分水岭”。许多开发者在日常开发中“能用就行”,一旦面对面试官的连环追问,便暴露出知识体系的碎片化与底层理解的缺失。

本文将带你以“面试官视角”重新审视 Java 核心知识点,结合 UML 图解、流程图、时序图、性能对比表 等可视化手段,全面剖析 JVM 内存模型、多线程并发、集合框架源码、GC 机制、反射与泛型 等高频考点。

无论你是应届生、中级开发,还是准备冲击高级/资深岗位的工程师,这篇文章都将成为你掌握 Java 的“终极武器”。


🧩 第一章:Java 核心知识体系全景图

1.1 Java 技术栈分层架构

Java 语言基础
面向对象编程
异常处理
泛型与反射
集合框架
多线程并发
ArrayList, LinkedList
HashMap, ConcurrentHashMap
Thread, Runnable
线程池, Lock
volatile, synchronized
JVM 虚拟机
内存模型
类加载机制
垃圾回收 GC
字节码与 JIT

三大核心模块

  • 语言基础:语法、OOP、异常、泛型、反射。
  • 并发编程:线程、锁、线程池、并发容器。
  • JVM 机制:内存结构、GC、类加载、性能调优。

🧠 第二章:JVM 内存模型与垃圾回收机制

2.1 JVM 运行时数据区结构

存储类信息、常量、静态变量
对象实例、数组
局部变量、方法调用
当前线程执行的字节码行号
调用本地方法(C/C++)
JVM
+Method Area
+Heap
+Stack
+PC Register
+Native Method Stack
MethodArea
Heap
+Young Generation
+Old Generation
+Metaspace(JDK 8+)
Stack
PCRegister
NativeStack
YoungGen
+Eden
+Survivor S0
+Survivor S1
OldGen
Metaspace

🔍 图解说明

  • 堆(Heap):所有线程共享,存放对象实例,是 GC 主要区域。
  • 方法区(Method Area):存储类元数据、常量池、静态变量(JDK 8 后为 Metaspace)。
  • 虚拟机栈(Stack):线程私有,存储局部变量、操作数栈、方法出口等。
  • 程序计数器(PC Register):记录当前线程执行的字节码指令地址。
  • 本地方法栈:为 Native 方法服务。
    阿里云38元每年起:https://www.aliyun.com/minisite/goods?userCode=ifzmrq1c

2.2 垃圾回收(GC)机制详解

2.2.1 分代收集理论
存活
存活
对象创建
Eden 区
Minor GC
Survivor S0
再次 Minor GC
Survivor S1
年龄 >= 15
Old Generation
回到 S0/S1
Major GC / Full GC
清理老年代

分代假说

  • 弱代假说:大多数对象朝生夕死。
  • 强代假说:熬过多次 GC 的对象更可能长期存活。

2.2.2 常见垃圾收集器对比
收集器 年轻代/老年代 算法 特点 适用场景
Serial Y / O 复制 / 标记-整理 单线程,简单高效 Client 模式
ParNew Y / O 复制 / 标记-整理 多线程,配合 CMS 多核服务器
Parallel Scavenge Y / O 复制 / 标记-整理 吞吐量优先 后台批处理
CMS O 标记-清除 低延迟,但有碎片 响应时间敏感
G1 Y+O 标记-复制 可预测停顿,大堆 大内存(>6GB)
ZGC Y+O 染色指针 <10ms 停顿,TB 级堆 超大堆、低延迟
Shenandoah Y+O Brooks 指针 与 ZGC 类似,开源 OpenJDK 用户

G1 收集器内存布局

G1 Heap
Region 1
Region 2
Region 3
...
Region N
Eden
Survivor
Old
Humongous 大对象

🔄 第三章:多线程与并发编程核心机制

3.1 线程状态转换图

start()
CPU 调度
synchronized 竞争失败
Object.wait(), Thread.join()
获取锁
notify()/notifyAll()
超时或中断
run() 结束
New
Runnable
Running
Blocked
sleep(), wait(timeout)
Timed
Terminated

六种线程状态

  • NEW:新建,未启动。
  • RUNNABLE:就绪或运行中。
  • BLOCKED:等待进入 synchronized 块。
  • WAITING:无限等待(需显式唤醒)。
  • TIMED_WAITING:限时等待。
  • TERMINATED:终止。

3.2 synchronizedReentrantLock 深度对比

特性 synchronized ReentrantLock
来源 JVM 内置关键字 JDK API(java.util.concurrent.locks
锁类型 非公平(JDK 6+ 优化为偏向锁) 默认非公平,可配置公平锁
可中断 lockInterruptibly()
超时获取 tryLock(timeout)
条件队列 wait()/notify() Condition.await()/signal()
锁分离 ✅ 多个 Condition
性能 JDK 6+ 优化后接近 ReentrantLock 高并发下略优
// ReentrantLock 使用示例
ReentrantLock lock = new ReentrantLock();
Condition notFull = lock.newCondition();
Condition notEmpty = lock.newCondition();

lock.lock();
try {
    while (queue.size() == capacity) {
        notFull.await(); // 等待队列不满
    }
    queue.add(item);
    notEmpty.signal(); // 通知消费者
} finally {
    lock.unlock();
}

3.3 线程池核心参数与工作流程

3.3.1 ThreadPoolExecutor 构造参数
参数 类型 说明
corePoolSize int 核心线程数,即使空闲也保留
maximumPoolSize int 最大线程数
keepAliveTime long 非核心线程空闲存活时间
unit TimeUnit 时间单位
workQueue BlockingQueue 任务队列
threadFactory ThreadFactory 线程创建工厂
handler RejectedExecutionHandler 拒绝策略

3.3.2 线程池工作流程图
提交任务
线程数 < corePoolSize?
创建新线程执行
队列未满?
任务入队
线程数 < maxPoolSize?
创建新线程执行
执行拒绝策略

四种拒绝策略

  • AbortPolicy:抛出 RejectedExecutionException(默认)。
  • CallerRunsPolicy:由调用线程执行任务。
  • DiscardPolicy:静默丢弃任务。
  • DiscardOldestPolicy:丢弃队列中最老任务,重试提交。

3.4 volatile 关键字与内存屏障

3.4.1 volatile 的三大特性
特性 说明
可见性 一个线程修改变量,其他线程立即可见
有序性 禁止指令重排序(插入内存屏障)
不保证原子性 i++ 仍需 synchronizedAtomicInteger
public class VolatileExample {
    private volatile boolean flag = false;
    
    public void writer() {
        a = 42;           // 1
        flag = true;      // 2 - volatile 写,插入 StoreStore 屏障
    }
    
    public void reader() {
        if (flag) {       // 3 - volatile 读,插入 LoadLoad 屏障
            System.out.println(a); // 4
        }
    }
}

内存屏障类型

  • LoadLoad:禁止屏障前的 Load 与屏障后的 Load 重排序。
  • StoreStore:禁止屏障前的 Store 与屏障后的 Store 重排序。
  • LoadStore:禁止屏障前的 Load 与屏障后的 Store 重排序。
  • StoreLoad:禁止屏障前的 Store 与屏障后的 Load 重排序(最重)。
    阿里云38元每年起:https://www.aliyun.com/minisite/goods?userCode=ifzmrq1c

📦 第四章:集合框架源码深度解析

4.1 HashMap 底层结构与扩容机制

4.1.1 JDK 8 后的数组 + 链表 + 红黑树结构
数组元素
链表转红黑树
next (链表)
HashMap
+Node[] table
+int size
+int threshold
+float loadFactor
Node
+final int hash
+final K key
+V value
+Node next
TreeNode
+TreeNode parent
+TreeNode left
+TreeNode right
+boolean red

关键参数

  • 初始容量DEFAULT_INITIAL_CAPACITY = 16
  • 负载因子DEFAULT_LOAD_FACTOR = 0.75
  • 树化阈值TREEIFY_THRESHOLD = 8
  • 反树化阈值UNTREEIFY_THRESHOLD = 6
  • 最小树化容量MIN_TREEIFY_CAPACITY = 64

4.1.2 扩容(resize)流程
HashMap OldTable NewTable 扩容条件:size > threshold 创建两倍大小的新数组 遍历旧数组 遍历链表或红黑树 重新计算索引(hash & (newCap-1)) 拆分为高低位两个链表 转为红黑树插入 alt [链表长度 <= 6] [链表长度 > 6] loop [每个桶] 替换 table 指向新数组 更新 threshold HashMap OldTable NewTable

JDK 8 扩容优化:利用 hash & oldCap 判断是否扩容后索引不变,避免重复 hash() 计算。


4.2 ConcurrentHashMap 线程安全实现

4.2.1 JDK 8 的 synchronized + CAS 机制
graph TD
    A[ConcurrentHashMap] --> B[Node<K,V>[] table]
    B --> C[Node 1]
    B --> D[Node 2]
    C --> E[链表/红黑树]
    D --> F[链表/红黑树]
    
    style C fill:#f44336, color:white
    style D fill:#f44336, color:white
    
    subgraph 线程安全
        C --> G[synchronized 锁住链表头节点]
        D --> H[CAS 操作头节点]
    end

核心思想

  • 使用 volatile 保证 table 可见性。
  • 插入时,对链表头节点加 synchronized 锁。
  • 扩容时,使用 CAS 更新 sizeCtl 控制并发。
  • 支持并发扩容(ForwardingNode 标记迁移中)。

🪄 第五章:反射、泛型与动态代理

5.1 Java 反射机制核心类图

getDeclaredFields()
getDeclaredMethods()
getDeclaredConstructors()
返回类对象
Class
Field
Method
Constructor
Object
+getClass()

反射典型用法

Class<?> clazz = Class.forName("com.example.User");
Constructor<?> ctor = clazz.getConstructor(String.class);
Object obj = ctor.newInstance("Alice");
Method method = clazz.getMethod("getName");
String name = (String) method.invoke(obj);

5.2 泛型类型擦除与桥接方法

5.2.1 类型擦除示例
public class Box<T> {
    private T value;
    
    public T getValue() { return value; }
    public void setValue(T value) { this.value = value; }
}

// 编译后等价于
public class Box {
    private Object value;
    
    public Object getValue() { return value; }
    public void setValue(Object value) { this.value = value; }
    
    // 桥接方法(Bridge Method)
    public void setValue(java.lang.String); // 不存在
}

桥接方法作用:确保多态调用正确性,由编译器自动生成。


5.3 动态代理两种实现方式

5.3.1 JDK 动态代理(基于接口)
Client Proxy InvocationHandler RealSubject getProxyInstance() invoke() method.invoke() result result result Client Proxy InvocationHandler RealSubject

要求:目标类必须实现接口。


5.3.2 CGLIB 动态代理(基于继承)
setCallback()
invokeSuper()
Target
ProxyextendsTarget
MethodInterceptor
Proxy

要求:目标类不能是 final,方法不能是 privatefinal


📊 第六章:高频面试题汇总与答案要点

问题 答案要点
String 为什么是不可变的? final 类、final char[]、无 setter、hash 缓存
String, StringBuilder, StringBuffer 区别? 不可变 vs 可变;线程安全(StringBuffer)vs 性能(StringBuilder)
equals== 区别? == 比较地址;equals 比较内容(可重写)
hashCodeequals 关系? equals 为 true,hashCode 必须相等;反之不一定
final 关键字作用? 类不可继承、方法不可重写、变量不可修改
static 关键字作用? 静态变量/方法属于类,非实例;静态块用于初始化
try-catch-finally 中 return 执行顺序? finally 一定执行,若 finally 有 return,则覆盖 try/catch 中的 return
ThreadLocal 原理与内存泄漏? 线程私有 Map,Key 为弱引用,Value 强引用,需手动 remove()

阿里云38元每年起:https://www.aliyun.com/minisite/goods?userCode=ifzmrq1c

更多推荐