1. Java基础复习的必要性与目标
最近在整理技术笔记时,发现很多Java基础知识点在实际工作中经常被忽略,但恰恰是这些基础概念决定了代码质量和系统稳定性。这份笔记源于我在团队内部的技术分享,经过多次迭代完善,特别适合1-3年经验的开发者查漏补缺。
不同于教科书式的罗列,我会结合线上事故案例和性能优化经验,重点讲解那些容易被误解的核心概念。比如字符串拼接的底层实现差异、集合类的线程安全陷阱等,都是面试和codereview中的高频考点。
2. 核心语言特性深度解析
2.1 面向对象三大特性的工程实践
封装性在实际项目中常被滥用,我曾见过用30多个getter/setter的"贫血模型"。合理的封装应该:
- 对修改关闭:使用final修饰关键字段
- 对扩展开放:通过接口暴露必要能力
- 典型反例:public的集合字段直接暴露给外部
继承体系的设计误区更常见:
// 错误示范:多层继承导致脆弱基类问题 class Animal {} class Dog extends Animal {} class PoliceDog extends Dog {} // 改进方案:组合优于继承 class PoliceDog { private Dog dog; private PoliceSkill skill; }2.2 异常处理的最佳实践
很多团队对异常使用存在认知偏差:
- 检查异常(Checked Exception)过度使用会导致代码污染
- 非检查异常(RuntimeException)滥用会掩盖问题
推荐的处理策略:
- 业务异常:定义明确的异常体系
public class BizException extends RuntimeException { private ErrorCode code; // 包含足够上下文信息 }- 技术异常:适当包装原生异常
- 全局异常处理器统一处理(Spring中@ControllerAdvice)
重要原则:永远不要吞掉异常!至少记录日志
3. 集合框架的隐藏陷阱
3.1 ArrayList的扩容机制实测
通过JMH基准测试发现:
// 初始化时不指定容量 List<Integer> list = new ArrayList<>(); // 首次add触发扩容到10 // 后续每次扩容增加50%容量性能对比测试结果:
| 操作 | 预设容量(ms) | 默认扩容(ms) |
|---|---|---|
| 添加10w元素 | 45 | 68 |
| 添加100w元素 | 320 | 510 |
3.2 HashMap的死循环问题
JDK7的HashMap在多线程resize时可能产生环形链表。关键代码段:
void transfer(Entry[] newTable) { // 旧版头插法会导致链表逆序 Entry<K,V> next = e.next; e.next = newTable[i]; newTable[i] = e; e = next; }解决方案:
- 使用ConcurrentHashMap
- 升级到JDK8+(改为尾插法)
- 必要时加锁(但性能下降)
4. 并发编程核心要点
4.1 线程状态转换的实战观察
通过jstack抓取的典型线程状态:
- BLOCKED:竞争synchronized锁
- WAITING:调用Object.wait()
- TIMED_WAITING:Thread.sleep()
诊断案例:
# 查找死锁(输出包含deadlock信息) jstack -l <pid> | grep -A 10 deadlock4.2 volatile的语义误区
常见误解:
- 认为volatile保证原子性(实际只保证可见性)
- 误用于复合操作(如i++)
正确使用场景:
- 状态标志位
volatile boolean shutdown;- 单例模式的双检锁
private volatile static Singleton instance;5. JVM内存模型精要
5.1 对象内存布局示例
通过JOL工具查看对象结构:
// 添加依赖:org.openjdk.jol:jol-core System.out.println(ClassLayout.parseInstance(obj).toPrintable());典型输出(64位JVM):
OFFSET SIZE TYPE DESCRIPTION 0 4 (object header) # Mark Word 12 4 int MyObject.value # 实例字段5.2 GC日志分析实战
启用详细GC日志:
-XX:+PrintGCDetails -Xloggc:/path/to/gc.log关键指标解析:
- Young GC耗时:通常应<50ms
- Full GC频率:超过1次/小时需警惕
- 老年代占用:持续超过75%应考虑扩容
6. 常用工具链技巧
6.1 诊断CPU飙升的步骤
- top定位高CPU进程
- top -Hp 找问题线程
- printf "%x\n" 转16进制
- jstack | grep -A 20
6.2 内存泄漏排查方案
MAT工具使用流程:
- 导出堆转储文件
jmap -dump:format=b,file=heap.hprof <pid>- 分析支配树(Dominator Tree)
- 检查GC Roots引用链
7. 编码规范中的技术本质
7.1 equals/hashCode契约
违反契约的灾难性后果:
- HashMap查找失效
- HashSet出现重复元素
正确实现模板:
@Override public boolean equals(Object o) { if (this == o) return true; if (!(o instanceof MyClass)) return false; MyClass that = (MyClass) o; return Objects.equals(field1, that.field1) && field2 == that.field2; } @Override public int hashCode() { return Objects.hash(field1, field2); }7.2 枚举的高级用法
优于常量的特性:
- 类型安全
- 内置方法
- 可添加行为
示例:
public enum Operation { PLUS { public double apply(double x, double y) { return x + y; } }, MINUS { public double apply(double x, double y) { return x - y; } }; public abstract double apply(double x, double y); }在整理这些基础知识点时,发现很多"常识"其实存在认知偏差。比如最近排查的一个性能问题,根源竟是开发者在循环里误用了String的+拼接。基础不牢地动山摇,建议每半年系统回顾一次核心概念。