外观
Java 基础 速查卡
🎯 覆盖 29 题 | ⭐ 高频 9 题 | 预计扫描 11 分钟 📌 先看⭐一句话答案 → 展开要点 → 自测清单检验
一、关键字与基础语法
知识地图:final(不可变) / finally(必执行) / finalize(GC回调,已废弃)
⭐ 重载 vs 重写
一句话: 重载 = 同一类中方法同名不同参(编译期静态绑定);重写 = 子类替换父类方法(运行期动态绑定,多态基础)。
| 维度 | 重载 Overload | 重写 Override |
|---|---|---|
| 位置 | 同一个类 | 子类对父类 |
| 参数列表 | 必须不同 | 必须相同 |
| 绑定时机 | 编译期(静态) | 运行期(动态,多态) |
| static 方法 | 可以重载 | 不能重写(只能隐藏) |
二、集合框架
知识地图:ArrayList(数组) / LinkedList(链表) / HashMap(数组+链表+红黑树) / ConcurrentHashMap(CAS+synchronized)
⭐ ArrayList vs LinkedList
一句话: 绝大多数场景用 ArrayList(连续内存 + CPU 缓存友好),LinkedList 几乎不用(队列/栈首选 ArrayDeque)。
| 维度 | ArrayList | LinkedList |
|---|---|---|
| 底层 | 动态数组 | 双向链表 |
| 随机访问 | O(1) | O(n) |
| 头部插删 | O(n) | O(1) |
| 缓存友好 | ✅ 连续内存 | ❌ 节点散布 |
ArrayList 扩容: 新容量 = 旧容量 × 1.5(oldCap + (oldCap >> 1)),Arrays.copyOf 复制;建议已知大小时初始化指定容量
⭐ HashMap 底层结构
一句话: JDK 8 的 HashMap = 数组 + 链表 + 红黑树(链表长度 ≥ 8 且数组 ≥ 64 时树化),通过扰动函数(高16位异或低16位)减少哈希碰撞。
数组 Node[] table
├── index i: null
├── index j: Node → Node → Node(链表,哈希冲突)
└── index k: TreeNode(红黑树,链表≥8转换)put 流程: hash(key) → 定桶 (n-1)&hash → 空桶直接放 → 冲突则遍历链表/树 → key 相同覆盖 → 链表尾插 → ≥8 树化 → size > threshold 扩容
⚠️ 易错:JDK 7 用头插法(并发扩容会死循环),JDK 8 改为尾插法(修复死循环但仍有数据丢失)
⭐ HashMap 扩容
一句话: 当 size > capacity × 0.75 时触发扩容,新容量翻倍;JDK 8 优化——只需看 hash 新增的那一位是 0 还是 1,决定元素留原位还是移到原位+旧容量。
旧容量16(10000) → 新容量32(100000)
元素去向只看 hash 的第5位:= 0 留原位,= 1 移到原位+16
→ 无需重新计算 hash,只需一次位运算 (e.hash & oldCap)负载因子 0.75: 时间(碰撞率)和空间(浪费率)的折中,泊松分布下碰撞概率最低
⭐ ConcurrentHashMap JDK 7 vs 8
一句话: JDK 7 用 Segment 分段锁(ReentrantLock,并发度=16),JDK 8 改为 CAS + synchronized 桶级别锁(并发度=数组长度,更细粒度)。
| 维度 | JDK 7 | JDK 8 |
|---|---|---|
| 锁机制 | ReentrantLock(Segment级) | synchronized(桶级) + CAS |
| 锁粒度 | 一个 Segment(多桶) | 单个桶(最细) |
| 并发度 | 固定16 | 理论=数组长度 |
| 数据结构 | 数组+链表 | 数组+链表+红黑树 |
| size() | 先无锁尝试,失败全锁 | CounterCell(LongAdder思想) |
JDK 8 写入流程: 空桶 → CAS 无锁插入;非空桶 → synchronized 锁桶头节点
⚠️ 易错:JDK 8 用 synchronized 而非 ReentrantLock,因为 JDK 6 后 synchronized 优化后(偏向/轻量/升级)性能已不输 RL
三、IO 模型
⭐ BIO / NIO / AIO
一句话: BIO 一连接一线程(阻塞),NIO 多路复用一线程管多连接(Selector/epoll),AIO 全异步但 Linux 支持有限实际用 NIO(Netty)。
| 模型 | 特点 | 底层 | 场景 |
|---|---|---|---|
| BIO | 同步阻塞,一连接一线程 | — | 并发量小 |
| NIO | 同步非阻塞,Selector 多路复用 | epoll | 高并发(Netty) |
| AIO | 异步非阻塞,内核完成后回调 | Linux 用 epoll 模拟 | 较少使用 |
NIO 三大核心: Channel(双向通道) + Buffer(读写缓冲) + Selector(事件监听)
epoll 核心: 红黑树存 fd + 就绪链表 + 事件回调;对比 select:fd 只注册一次 + 只返回就绪的 + 无 fd 上限
四、Java 17-21 现代特性
⭐ Java 17-21 六大新特性
一句话: Record(不可变数据类) + Sealed Classes(控制继承) + Pattern Matching(switch 类型匹配) + Virtual Threads(轻量线程) + Text Blocks + instanceof 自动绑定。
| 特性 | 版本 | 一句话 |
|---|---|---|
| Record | JDK 16 | 一行定义不可变数据类,自动生成 equals/hashCode/toString |
| Sealed Classes | JDK 17 | permits 限制谁能继承,配合 switch 做穷举检查 |
| Pattern Matching switch | JDK 21 | switch 支持类型模式 + when 守卫条件 |
| Virtual Threads | JDK 21 | JVM 调度的轻量线程,百万级并发,IO 阻塞自动让出 |
| Text Blocks | JDK 15 | 三引号 """ 多行字符串 |
| instanceof 绑定 | JDK 16 | if (obj instanceof String s) 自动类型转换 |
补充速览
| 关键词 | 核心答案 |
|---|---|
| final | 变量:值不可变(引用类型:地址不可变,内容可变); 方法:不可重写; 类:不可继承 |
| finally | 必执行(除非 System.exit/JVM 崩溃); try 有 return 先暂存 → finally → 再返回 |
| equals+hashCode | 必须同时重写,否则 HashMap 定位桶错误(hashCode不同→桶不同→get 返回 null) |
| 基本类型 | 8种: byte(1)/short(2)/int(4)/long(8)/float(4)/double(8)/char(2)/boolean |
| Integer 缓存 | -128~127 缓存,== 为 true;超范围 == 为 false,用 equals |
| 深拷贝 vs 浅拷贝 | 浅:引用类型只复制地址(共享); 深:递归复制所有(独立); 实现:手动/clone/序列化 |
| 四种引用 | 强(不回收) > 软(OOM前回收) > 弱(下次GC必回收,ThreadLocal的key) > 虚(随时) |
| 集合全景 | List:ArrayList/LinkedList; Set:HashSet/TreeSet; Map:HashMap/ConcurrentHashMap/TreeMap |
| 链表≥8转红黑树 | 泊松分布下链表=8概率仅千万分之六;红黑树写操作比AVL旋转少;退化阈值=6(避免频繁转换) |
| Redis Hash vs Java HashMap | Redis 渐进式rehash(不阻塞); Redis 无红黑树(单线程+field数量有限); 负载因子1(vs 0.75) |
| ⭐ 泛型类型擦除 | 编译期检查 + 运行期擦除为 Object/上界;不能 new T/new T[]/instanceof 泛型 |
| ⭐ PECS | Producer Extends(读,上界通配符) / Consumer Super(写,下界通配符) |
| ⭐ 反射 | Class.forName → getDeclaredMethod → setAccessible → invoke;比直接调用慢5~50倍 |
| JDK代理 vs CGLIB | JDK:基于接口(Proxy+InvocationHandler); CGLIB:基于继承(Enhancer); Boot 2.x+默认CGLIB |
| ⭐ Stream 三段式 | 数据源→中间操作(惰性,filter/map/flatMap)→终端操作(触发,collect/reduce/forEach) |
| parallelStream | 底层 ForkJoinPool.commonPool(); 不适合IO密集/共享可变状态/小数据量 |
🧠 助记汇总
| 口诀 | 含义 |
|---|---|
| 重载编译,重写运行 | 重载=编译期静态绑定,重写=运行期动态绑定 |
| 数链红 | HashMap: 数组+链表+红黑树 |
| 8树6链 | 链表≥8转红黑树,≤6退回链表 |
| CAS空桶,sync非空 | ConcurrentHashMap JDK8 写入策略 |
| 记密文匹虚块 | Java 17-21: Record/Sealed/Pattern/Virtual/TextBlock/instanceof |
✅ 自测清单
| # | 问题 | 你能说出... |
|---|---|---|
| 1 | 重载 vs 重写 | 4 个核心区别 |
| 2 | HashMap 结构 | 底层结构 + put 完整流程 |
| 3 | HashMap 扩容 | 触发条件 + JDK8 优化原理 |
| 4 | ConcurrentHashMap | JDK 7 vs 8 的锁机制对比 |
| 5 | BIO/NIO/AIO | 三者区别 + epoll 核心优势 |
| 6 | 泛型 PECS | 类型擦除原理 + extends 读/super 写 |
| 7 | 反射与动态代理 | JDK 代理 vs CGLIB + Spring 默认选择 |
| 8 | Stream API | 惰性求值 + groupingBy/flatMap 编码题 |
| 6 | Java 17-21 | 六大新特性各一句话 |
| 7 | ArrayList vs LinkedList | 为什么实际几乎不用 LinkedList |
| 8 | equals/hashCode | 为什么必须同时重写 |
💡 首次全部过一遍 → 第2天只过答不上来的 → 第4天再复习 → 面试前一天最后扫一遍