Java 面试知识点梳理
·
Java 面试知识点梳理
定位:Java / 后端开发岗面试速通。
用法:每个模块先看"核心结论",再看"面试题",最后对照"易踩坑"。
一、Java 基础
1.1 面向对象三大特性
| 特性 | 说明 | 面试要点 |
|---|---|---|
| 封装 | 隐藏实现,暴露接口 | 访问修饰符 private/protected/public |
| 继承 | 子类复用父类 | 单继承;super 调用父类构造;方法重写 |
| 多态 | 父类引用指向子类对象 | 编译看左、运行看右;重写实现运行时绑定 |
1.2 重载 vs 重写
- 重载(overload):同一类、同名、参数列表不同(个数/类型/顺序),与返回值和访问修饰符无关。
- 重写(override):子类覆盖父类方法,方法签名一致;访问权限不能更严,抛出的异常不能更宽。
1.3 数据类型
- 8 种基本类型:
byte short int long float double char boolean,其余均为引用类型。 - 装箱/拆箱:
Integer等包装类缓存 -128~127(IntegerCache),==比较该区间会命中缓存。 String不可变:底层final char[](JDK9 后为byte[]),+拼接编译器优化为StringBuilder。
1.4 == 与 equals / hashCode
==:基本类型比值,引用类型比地址。equals:默认比地址,重写后比内容(String已重写)。hashCode:相等对象hashCode必相等;hashCode相等对象不一定equals相等。重写equals必须重写hashCode(否则 HashMap 失效)。
二、集合框架
2.1 体系概览
Collection
├─ List(有序可重复):ArrayList / LinkedList / Vector
└─ Set(不可重复):HashSet / LinkedHashSet / TreeSet
Map(键值对):HashMap / LinkedHashMap / TreeMap / Hashtable / ConcurrentHashMap
2.2 ArrayList vs LinkedList
| 维度 | ArrayList | LinkedList |
|---|---|---|
| 底层 | 动态数组 | 双向链表 |
| 随机访问 | O(1) | O(n) |
| 插入删除(中间) | O(n) 搬移 | O(1) 改指针 |
| 内存 | 连续,省 | 节点额外开销 |
2.3 HashMap(必考)
- JDK 1.8 结构:数组 + 链表 + 红黑树。默认容量 16,负载因子 0.75,阈值 = 容量 × 0.75。
- 扩容:超过阈值 resize 为 2 倍,元素重新散列(低位/高位拆分,无需重算 hash)。
- 链表树化:链表长度 ≥ 8 且数组容量 ≥ 64 转为红黑树;树节点 ≤ 6 退化为链表。
- 线程不安全:并发
put可能数据覆盖或死循环(1.7 头插;1.8 已修复死循环但仍不安全)。
2.4 ConcurrentHashMap
- JDK 1.7:
Segment分段锁(继承 ReentrantLock),默认 16 段并发度 16。 - JDK 1.8:
Node数组 + 链表/红黑树,put用 CAS + synchronized(锁单个桶头节点),更细粒度,效率更高。
三、并发编程(重灾区)
3.1 线程的创建
- 继承
Thread/ 实现Runnable/ 实现Callable(有返回值、Future获取)/ 线程池。
3.2 线程状态
NEW → RUNNABLE → BLOCKED / WAITING / TIMED_WAITING → TERMINATED
sleep:不释放锁,休眠后自动恢复。wait:释放锁,需notify/notifyAll唤醒(必须在synchronized内)。
3.3 synchronized 与 ReentrantLock
| 维度 | synchronized | ReentrantLock |
|---|---|---|
| 实现 | JVM 内置(监视器锁) | API 层面(AQS) |
| 释放 | 自动(代码块结束/异常) | 手动 unlock(放 finally) |
| 公平 | 非公平 | 可公平/非公平 |
| 中断 | 不可中断 | 可中断 lockInterruptibly |
| 条件 | 单一等待队列 | 多 Condition |
synchronized 锁升级:无锁 → 偏向锁 → 轻量级锁(CAS 自旋)→ 重量级锁(操作系统互斥)。
3.4 线程池(必考)
7 个参数:
corePoolSize核心线程数maximumPoolSize最大线程数keepAliveTime空闲线程存活时间unit时间单位workQueue任务队列(ArrayBlockingQueue / LinkedBlockingQueue / SynchronousQueue)threadFactory线程工厂handler拒绝策略
处理流程:核心线程满 → 入队 → 队列满 → 开非核心线程 → 达最大线程 → 触发拒绝策略。
4 种拒绝策略:AbortPolicy(抛异常,默认)/ CallerRunsPolicy(调用者线程执行)/ DiscardPolicy(丢弃)/ DiscardOldestPolicy(丢最旧)。
3.5 JMM 与三大特性
- 原子性:
synchronized、Lock、原子类(AtomicInteger)。 - 可见性:
volatile、synchronized、final。 - 有序性:
volatile禁止指令重排(happens-before原则)。 volatile不保证原子性(如i++非原子),适合状态标志位。- CAS:比较并交换,无锁乐观;ABA 问题用
AtomicStampedReference加版本号解决。 - AQS:抽象队列同步器,ReentrantLock/Semaphore/CountDownLatch 的底层基础(state + CLH 队列)。
四、JVM(高频)
4.1 运行时数据区
- 线程私有:程序计数器、虚拟机栈(栈帧/局部变量表)、本地方法栈。
- 线程共享:堆(对象实例,GC 主战场)、方法区(JDK8 后为元空间 Metaspace,存类信息/常量/静态变量)。
4.2 垃圾回收
- 判断存活:引用计数(循环引用失效)/ 可达性分析(GC Roots 不可达即回收,主流)。
- GC Roots:栈帧局部变量、静态变量、常量、JNI 引用。
- 回收算法:标记-清除(碎片)/ 标记-整理(慢)/ 复制(新生代,效率高)。
- 分代收集:新生代(Eden + 2 Survivor,Minor GC,复制算法)→ 老年代(Major/Full GC,标记-整理)。
- 垃圾回收器:Serial(单线程)/ Parallel(吞吐优先)/ CMS(并发标记清除,低停顿,已弃用)/ G1(Region 化,可预测停顿,主流)/ ZGC(TB 级、亚毫秒停顿)。
4.3 类加载
- 双亲委派:自底向上委托父加载器,父不能加载才自己加载;避免类重复、保证核心类安全。
- 破坏场景:SPI(JDBC)、热部署、Tomcat WebAppClassLoader。
- OOM 常见:堆溢出(
-Xmx调大/查内存泄漏)、栈溢出(递归过深)、元空间溢出(类加载过多)。
五、异常
Throwable→Error(严重,不可捕获,如 OOM)/Exception。Exception→RuntimeException(非受检,空指针/越界)/ 受检异常(必须 try 或 throws,如 IOException)。finally始终执行(除非System.exit);return前先执行finally(finally 的 return 会覆盖)。
六、反射与注解
- 反射:运行时获取类信息并操作(
Class.forName/getDeclaredMethod/setAccessible(true)突破私有)。代价:性能略低、破坏封装。 - 注解:
@Override/@Deprecated/@FunctionalInterface;元注解@Target@Retention@Documented@Inherited;@Retention(RUNTIME)才能反射读取。
七、Java 8+ 新特性
- Lambda:函数式接口(
@FunctionalInterface,仅一个抽象方法)。 - Stream API:
filter/map/reduce/collect,惰性求值、可并行(parallelStream)。 - Optional:优雅判空,避免 NPE。
- 接口默认方法:
default方法、静态方法。 - 新日期 API:
LocalDate/LocalDateTime/DateTimeFormatter(线程安全,替代SimpleDateFormat)。 - 方法引用:
::。
八、IO 与 NIO
- BIO:流(InputStream/OutputStream),阻塞、面向流。
- NIO:
Channel+Buffer+Selector,非阻塞、多路复用,适合高并发(Netty 基础)。 - AIO(NIO.2):异步回调。
九、易踩坑清单
| 坑 | 现象 | 解决 |
|---|---|---|
遍历 List 时 remove | ConcurrentModificationException | 用迭代器 remove 或 removeIf |
substring 内存泄漏(JDK6) | 长字符串截取后旧大字符串不释放 | JDK7+ 已修复(新建数组) |
用 == 比包装类 | -128~127 外为 false | 用 equals |
重写 equals 不写 hashCode | HashMap 查找失败 | 成对重写 |
i++ 多线程 | 结果不对 | AtomicInteger/synchronized |
SimpleDateFormat 多线程 | 日期错乱 | 局部变量 / DateTimeFormatter |
线程池用 Executors 创建 | OOM 风险(无界队列/无限线程) | 用 ThreadPoolExecutor 自定义 |
HashMap 并发写 | 数据丢失 | 用 ConcurrentHashMap |
十、高频面试题 30 连击
- 面向对象三大特性?
- 重载和重写区别?
==与equals区别?为何重写 equals 要重写 hashCode?- String 为什么不可变?
- Integer 缓存范围?
- ArrayList 与 LinkedList 区别?
- HashMap 底层结构与扩容?
- 为何链表 8 转红黑树?
- ConcurrentHashMap 1.7 与 1.8 区别?
- 创建线程有几种方式?
- sleep 与 wait 区别?
- synchronized 锁升级过程?
- synchronized 与 ReentrantLock 区别?
- volatile 能保证原子性吗?
- 线程池 7 参数与处理流程?
- 四种拒绝策略?
- 为什么不建议用 Executors 创建线程池?
- CAS 是什么?ABA 怎么解决?
- AQS 原理?
- JVM 内存区域划分?
- 何时发生栈溢出 / 堆溢出?
- 如何判断对象可回收?
- 垃圾回收算法有哪些?
- G1 与 CMS 区别?
- 双亲委派模型及破坏场景?
- 类加载过程?
- 受检与非受检异常区别?
- 反射的原理与代价?
- Java 8 有哪些新特性?
- BIO、NIO、AIO 区别?
openEuler 是由开放原子开源基金会孵化的全场景开源操作系统项目,面向数字基础设施四大核心场景(服务器、云计算、边缘计算、嵌入式),全面支持 ARM、x86、RISC-V、loongArch、PowerPC、SW-64 等多样性计算架构
更多推荐


所有评论(0)