乐途乐途
主页
  • 计算机基础

    • TCP/IP
    • Linux
    • HTTP
  • 数据库

    • SQL
    • MySQL 5.7
  • 编程语言

    • C
    • C++
    • Java SE
    • Python2
    • Python3
  • 数据格式

    • JSON
    • XML
  • 认证与安全

    • JWT
  • 工具

    • Markdown
  • Git

    • GitFlow
  • Quartz

    • Quartz
  • Java

    • Maven 入门
    • Maven 进阶
    • MyBatis
    • Spring
    • Spring MVC
  • Java

    • Spring Boot
    • Spring Cloud
    • Spring Cloud Alibaba
    • Spring Security
    • Spring AI
    • Spring Batch
    • Kafka
    • Java 设计模式
  • 缓存

    • Redis
  • 搜索引擎

    • Elasticsearch
  • 分布式协调

    • ZooKeeper
联系
阿里云
主页
  • 计算机基础

    • TCP/IP
    • Linux
    • HTTP
  • 数据库

    • SQL
    • MySQL 5.7
  • 编程语言

    • C
    • C++
    • Java SE
    • Python2
    • Python3
  • 数据格式

    • JSON
    • XML
  • 认证与安全

    • JWT
  • 工具

    • Markdown
  • Git

    • GitFlow
  • Quartz

    • Quartz
  • Java

    • Maven 入门
    • Maven 进阶
    • MyBatis
    • Spring
    • Spring MVC
  • Java

    • Spring Boot
    • Spring Cloud
    • Spring Cloud Alibaba
    • Spring Security
    • Spring AI
    • Spring Batch
    • Kafka
    • Java 设计模式
  • 缓存

    • Redis
  • 搜索引擎

    • Elasticsearch
  • 分布式协调

    • ZooKeeper
联系
阿里云
  • 学习路径
  • 第1章 Java概述与环境搭建

    • Java概述与环境搭建
    • Java语言概述
    • 解释型语言与编译型语言对比
    • JDK安装与配置
    • JDK、JRE、JVM 详解
    • HelloWorld程序详解
    • IDE 介绍
  • 第2章 标识符与基本数据类型

    • 章节导读
    • 变量概述
    • 常量概述
    • 基本类型与包装类
    • 字节型 byte
    • 短整型 short
    • 整型 int
    • 长整型 long
    • 单精度浮点型 float
    • 双精度浮点型 double
    • 字符型 char
    • 布尔型 boolean
    • 类型转换
  • 第3章 运算符与表达式

    • 章节导读
    • 算术运算符
    • 赋值运算符
    • 关系运算符
    • 逻辑运算符
    • 位运算符
    • 条件运算符
    • 运算符优先级
    • 表达式
  • 第4章 流程控制

    • 章节导读
    • 常见的程序运行流程
    • if-else 选择结构
    • switch 多分支选择
    • while 循环
    • do-while 循环
    • for 循环
    • break 与 continue
  • 第5章 数组

    • 章节导读
    • 一维数组
    • 多维数组
    • Arrays 工具类
  • 第6章 类与对象

    • 章节导读
    • 类与对象
    • 方法定义与调用
    • 构造方法
    • 封装
    • 访问修饰符
    • package 与 import
    • static 关键字
    • this 关键字
    • 参数传递 详解
    • 枚举
    • 成员内部类
    • 局部内部类
    • 静态内部类
    • 匿名内部类
  • 第7章 接口与继承

    • 章节导读
    • 继承
    • super 关键字
    • final 关键字
    • 多态
    • 向上转型与向下转型
    • 抽象类
    • 接口
    • 抽象类与接口对比
  • 第8章 注解

    • 章节导读
    • 注解基础
    • 元注解详解
    • 自定义注解
  • 第9章 常用类

    • 章节导读:Java 常用类
    • Object 类:万类之祖
    • 包装类:基本类型的对象化
    • String:不可变的字符串
    • StringBuffer:线程安全的可变字符串
    • StringBuilder:可变的字符串构建器
    • Math:数学运算工具类
    • Random:伪随机数生成器
    • 大数值运算 详解
    • 日期时间API 详解
  • 第10章 异常机制

    • 章节导读
    • 异常体系与分类
    • try-catch-finally
    • try-with-resources
    • throws 与 throw
    • 自定义异常
  • 第11章 泛型

    • 章节导读
    • 泛型基础
    • 通配符与PECS原则
    • 类型擦除
  • 第12章 集合框架

    • 章节导读
    • 集合框架概述
    • ArrayList
    • LinkedList
    • HashMap 详解
    • LinkedHashMap 详解
    • TreeMap 详解
    • HashSet
    • TreeSet 详解
    • TreeSet 与 Comparable
    • Collections 工具类详解
  • 第13章 IO流

    • 章节导读
    • IO流概述
    • 字节流
    • 字符流
    • 缓冲流
    • 转换流 详解
    • 序列化 详解
    • NIO与Files 详解
    • NIO与Files工具类
  • 第14章 多线程与并发

    • 第十六章 多线程与并发 —— 章节导读
    • 线程基础详解
    • synchronized 详解
    • Lock 与显式锁详解
    • volatile 详解
    • wait 与 notify 详解
    • ThreadLocal详解
    • 原子类详解
    • 并发工具类详解
    • 线程池详解
  • 第15章 反射

    • 章节导读
    • 反射概述与 Class 对象
    • Constructor 与对象创建
    • Field与Method详解
    • 反射应用详解
  • 第16章 JDK8新特性

    • 章节导读
    • Lambda 表达式
    • Stream API 基础
    • Stream API 高级详解
    • Optional 详解
    • 新日期时间API详解
  • 第17章 JDK9-11新特性

    • 章节导读
    • 模块化系统 — Project Jigsaw(JDK 9)
    • var 局部变量类型推断(JDK 10)
    • 集合工厂方法与增强(JDK 9 / 10 / 11)
    • 接口增强:private 方法(JDK 9)
    • Stream API 增强(JDK 9)
    • Optional 增强(JDK 9 / 10 / 11)
    • String 新增方法(JDK 11)
    • HTTP Client 与 Files 增强(JDK 11)
    • 直接运行 Java 源文件 — JEP 330(JDK 11)
  • 第18章 JDK12-17新特性

    • 章节导读
    • Switch 表达式(JDK 12 预览 / JDK 14 正式)
    • 文本块 Text Blocks(JDK 13 预览 / JDK 15 正式)
    • Records 记录类(JDK 14 预览 / JDK 16 正式)
    • 密封类 Sealed Classes(JDK 15 预览 / JDK 17 正式)
    • instanceof 模式匹配(JDK 14 预览 / JDK 16 正式)
    • Switch 模式匹配 — Pattern Matching for switch(JDK 17 预览 / JDK 21 正式)
    • Helpful NPE 与 String 增强(JDK 12 / JDK 14 / JDK 15)
    • Stream 增强(JDK 12 / JDK 16)
    • 日期时间增强 — Day Period 支持(JDK 16)
  • 第19章 JDK18-21新特性

    • 章节导读
    • 虚拟线程(JDK 19 预览 / JDK 20 第二预览 / JDK 21 正式)
    • 序列集合(JDK 21 正式)
    • Switch 模式匹配(JDK 17 预览 / JDK 18 第二预览 / JDK 20 第四预览 / JDK 21 正式)
    • Record 模式匹配(JDK 19 预览 / JDK 20 第二预览 / JDK 21 正式)
    • 未命名模式与变量(JDK 21 预览 / JDK 22 正式)
  • 第20章 JDK 22-25 新特性

    • 章节导读
    • 字符串模板(JDK 22 预览 / JDK 23 第二预览 / JDK 24 第三预览)
    • Stream Gatherers(JDK 22 预览 / JDK 24 第二预览)
    • 隐式声明类与实例方法(JDK 23 预览 / JDK 24 第二预览)
    • 原始类型模式匹配(JDK 24 预览)
  • 附录

    • Java 核心知识点
    • Java SE 专业术语
    • Java特性索引(JDK 8 → 25)

Java 核心知识点

学习哲学:以"面向对象、集合框架、并发编程、JVM原理"为骨架,以 Oracle 官方 Java Tutorials 为锚点,以 IDEA 调试和 JVM 监控为手术刀,以真实企业级后端开发为验收标准。

版本说明:本教程以 Java SE 8 (LTS) 为基线,标注 Java 8/9/11/14/17/21 等关键版本的新特性。标记 [JDK x+] 表示自该版本起可用。


第一阶段:Java 概述与开发环境

1.1 Java 是什么

Java 是 Sun Microsystems(后被 Oracle 收购)于 1995 年发布的面向对象编程语言,核心理念是 "Write Once, Run Anywhere"(一次编写,到处运行)。Java 程序编译为字节码后在 JVM(Java Virtual Machine) 上运行,屏蔽了底层操作系统差异。

Java 三大平台:

平台全称定位
Java SEStandard Edition核心基础,包含语言规范、核心 API、JVM
Java EE(Jakarta EE)Enterprise Edition企业级 Web/分布式应用,构建在 SE 之上
Java MEMicro Edition嵌入式与移动设备

JDK 关键 LTS 版本:

版本发布时间核心新特性
Java 8 (LTS)2014.03Lambda、Stream API、Optional、新日期时间 API
Java 11 (LTS)2018.09HTTP Client、var 局部变量推断(10)、模块化(9)
Java 17 (LTS)2021.09Record、Sealed Class、Pattern Matching for switch(预览)
Java 21 (LTS)2023.09Virtual Thread、Record Pattern、Pattern Matching for switch(正式)

1.2 JVM / JRE / JDK 关系

职责划分:

组件职责
JDK开发工具包,包含 JRE + 编译器(javac)、打包工具(jar)、文档工具(javadoc)等
JRE运行环境,包含 JVM + 核心类库,仅能运行 Java 程序不能编译
JVM虚拟机,执行字节码,负责内存管理、垃圾回收、线程调度、安全检查

从 Java 11 开始,Oracle 不再单独发布 JRE,JDK 本身即包含运行环境。

1.3 Java 程序编译与运行

编译命令:javac Hello.java → 生成 Hello.class运行命令:java Hello → JVM 执行字节码

1.4 本周实践任务

  • [ ] 安装 JDK 17 或 21,配置 JAVA_HOME 和 PATH 环境变量
  • [ ] 用 javac 和 java 命令手工编译运行一个 HelloWorld
  • [ ] 用 javap -c Hello 反编译 class 文件,观察字节码指令
  • [ ] 运行 jshell(Java 9+ 交互式编程环境)体验快速代码验证
  • [ ] 对比 java -version 输出的不同 JDK 版本信息

第二阶段:语言基础

2.1 数据类型

Java 是强类型语言,每个变量必须先声明类型。数据类型分为基本类型(Primitive Type)和引用类型(Reference Type)。

8 种基本类型:

类型大小默认值范围包装类
byte1 字节0-128 ~ 127Byte
short2 字节0-32768 ~ 32767Short
int4 字节0-2³¹ ~ 2³¹-1(约 ±21 亿)Integer
long8 字节0L-2⁶³ ~ 2⁶³-1Long
float4 字节0.0f±3.4E-38 ~ ±3.4E+38(6-7 位有效数字)Float
double8 字节0.0d±1.7E-308 ~ ±1.7E+308(15 位有效数字)Double
char2 字节'\u0000'0 ~ 65535(Unicode 字符)Character
booleanJVM 依赖falsetrue / falseBoolean

boolean 大小未精确定义,JVM 中通常用 int 表示,数组中以 byte 存储。

引用类型:类(Class)、接口(Interface)、数组(Array)、枚举(Enum)、注解(Annotation)、记录(Record [JDK 14+])。

基本类型 vs 包装类:

特性基本类型包装类
存储位置栈(局部变量)/ 堆(成员变量)堆
默认值数值型 0,boolean falsenull
泛型支持❌ 不支持✅ 支持
性能高较低(装箱开销)
方法调用无有工具方法
int a = 100;                    // 基本类型
Integer b = Integer.valueOf(100); // 包装类(推荐,复用缓存 -128~127)
Integer c = 100;                 // 自动装箱(Auto-boxing,编译后等价于 Integer.valueOf(100))
int d = c;                       // 自动拆箱(Unboxing)

2.2 变量

Java 变量分三类:

变量类型声明位置生命周期默认值
局部变量方法/代码块内方法执行期间❌ 无默认值,必须显式初始化
成员变量(实例变量)类中,方法外,无 static与对象共存亡✅ 有默认值(0 / false / null)
静态变量(类变量)类中,有 static类加载到卸载✅ 有默认值

局部变量类型推断 [JDK 10+]:

var list = new ArrayList<String>();  // 编译器推断为 ArrayList<String>
var name = "Hello";                   // 推断为 String
// var x;  ❌ 编译错误,必须初始化

var 仅用于局部变量,不能用于成员变量、方法参数、返回类型。

2.3 数组

// 声明与初始化
int[] arr1 = new int[5];              // 默认值 0
int[] arr2 = {1, 2, 3, 4, 5};       // 静态初始化
int[] arr3 = new int[]{1, 2, 3};    // 匿名数组

// 多维数组
int[][] matrix = new int[3][4];
int[][] jagged = {{1, 2}, {3, 4, 5}}; // 锯齿数组

// 数组工具类
Arrays.sort(arr1);                     // 排序
Arrays.binarySearch(arr1, 3);          // 二分查找
Arrays.copyOf(arr1, 10);               // 扩容
Arrays.toString(arr1);                 // 打印

数组长度 length 是属性而非方法。数组一旦创建,长度不可变。

2.4 运算符

类别运算符说明
算术+ - * / %加减乘除取模
赋值= += -= *= /= %=赋值及复合赋值
自增自减++ --前缀(先运算后用)vs 后缀(先用后运算)
关系== != > < >= <=比较运算,结果为 boolean
逻辑&& || !短路与、短路或、非
位运算& | ^ ~ << >> >>>按位与/或/异或/非,左移,算数右移,逻辑右移
三元? :条件 ? 值1 : 值2

== vs equals():

String s1 = new String("hello");
String s2 = new String("hello");
System.out.println(s1 == s2);        // false,比较引用地址
System.out.println(s1.equals(s2));   // true,比较内容

== 比较基本类型的值或引用类型的地址;equals() 比较对象内容(需重写)。

2.5 流程控制

// if-else
if (condition) { ... } else if (condition2) { ... } else { ... }

// switch(支持 byte/short/int/char/String/枚举)
switch (value) {
    case 1: ... break;
    case 2: ... break;
    default: ...
}

Switch 表达式 [JDK 14+]:

String result = switch (day) {
    case MONDAY, FRIDAY -> "工作日";
    case SATURDAY, SUNDAY -> "周末";
    default -> "未知";
};

循环:

while (condition) { ... }
do { ... } while (condition);
for (int i = 0; i < 10; i++) { ... }
for (Type item : collection) { ... }  // 增强 for,适用于数组和 Iterable

分支:break(跳出循环)、continue(跳过本次迭代)、return(返回方法)、label(带标签的 break/continue)。

2.6 本周实践任务

  • [ ] 验证基本类型的默认值和取值范围
  • [ ] 用 javap -c 观察 Integer.valueOf(100) 是否走缓存
  • [ ] 对比 String s = "hello" 与 new String("hello") 的 == 和 equals 结果
  • [ ] 用 var 声明局部变量,观察 IDE 的类型推断提示
  • [ ] 用 Switch 表达式替代传统 switch-case,比较代码简洁度

第三阶段:面向对象编程(OOP)

3.1 OOP 四大基本特征

特征含义Java 实现
封装(Encapsulation)隐藏内部实现,仅暴露接口private + getter/setter
继承(Inheritance)子类复用父类属性和方法extends(单继承)
多态(Polymorphism)同一行为的不同表现形式方法重写 + 父类引用指向子类对象
抽象(Abstraction)提取共性忽略细节abstract 类 / interface

3.2 类与对象

public class Person {
    // 成员变量(字段)
    private String name;
    private int age;

    // 静态变量
    public static final String SPECIES = "Homo sapiens";

    // 构造方法
    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    // 实例方法
    public String getName() { return name; }

    // 静态方法
    public static void printSpecies() {
        System.out.println(SPECIES);
    }

    // 重写 Object 方法
    @Override
    public String toString() {
        return "Person{name='" + name + "', age=" + age + "}";
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (!(o instanceof Person)) return false;
        Person person = (Person) o;
        return age == person.age && Objects.equals(name, person.name);
    }

    @Override
    public int hashCode() {
        return Objects.hash(name, age);
    }
}

this 关键字的两种用法:① 引用当前对象实例;② 在构造方法中调用本类的其他构造方法 this(...)。

3.3 封装与访问控制

修饰符同类同包子类任何位置
private✅❌❌❌
default(无修饰符)✅✅❌❌
protected✅✅✅❌
public✅✅✅✅

JavaBean 规范:① 无参构造方法;② 属性私有化 private;③ 提供 getter/setter 方法;④ 实现 Serializable(可选)。

3.4 继承

Java 支持单继承(一个类只能有一个直接父类),所有类的最终祖先都是 java.lang.Object。

public class Student extends Person {
    private String school;

    public Student(String name, int age, String school) {
        super(name, age);  // 调用父类构造方法
        this.school = school;
    }

    @Override
    public String toString() {
        return "Student{" + super.toString() + ", school='" + school + "'}";
    }
}

方法重写(Override)vs 方法重载(Overload):

维度Override(重写)Overload(重载)
发生位置父子类之间同一个类中
方法签名完全相同方法名相同,参数列表不同
返回类型相同或协变(子类型)可以不同
访问修饰符不能更严格无限制
运行时动态绑定(多态)静态绑定(编译期决定)

@Override 注解让编译器检查是否真的是重写,强烈推荐使用。

super 关键字:① 调用父类构造方法 super(args)(必须放在子类构造方法首行);② 访问父类成员 super.method() / super.field。

3.5 多态

// 编译时类型 = Person,运行时类型可能是 Student
Person p = new Student("Alice", 20, "PKU");
p.getName();          // 调用 Person.getName() —— 不涉及多态
p.toString();         // 调用 Student.toString() —— 运行时多态

// 向下转型(需要确认类型)
if (p instanceof Student) {
    Student s = (Student) p;
    s.getSchool();
}

// Pattern Matching for instanceof [JDK 16+]
if (p instanceof Student s) {
    System.out.println(s.getSchool());
}

instanceof 模式匹配 [JDK 16+]:if (obj instanceof String s && s.length() > 5),一步完成类型判断和变量绑定。

3.6 抽象类与接口

维度抽象类(abstract class)接口(interface)
关键字abstract classinterface
构造方法✅ 有❌ 无
成员变量无限制只能 public static final 常量
方法抽象方法 + 具体方法抽象方法 + default 方法 [JDK 8+] + static 方法 [JDK 8+] + private 方法 [JDK 9+]
继承单继承 extends多实现 implements
设计意图"is-a" 关系,模板模式"can-do" 能力,行为契约
// 接口
public interface Flyable {
    void fly();                              // 抽象方法

    default void land() {                     // 默认方法 [JDK 8+]
        System.out.println("准备着陆...");
    }

    static String getType() {                 // 静态方法 [JDK 8+]
        return "飞行物";
    }

    private void checkWeather() {             // 私有方法 [JDK 9+]
        // 内部复用逻辑
    }
}

函数式接口(Functional Interface) [JDK 8+]:只有一个抽象方法的接口。@FunctionalInterface 注解标记。常见的有 Runnable、Comparator、Callable、Predicate、Function、Consumer、Supplier。

3.7 内部类

类型定义位置特点
成员内部类类中方法外可访问外部类所有成员,Outer.this.field
静态内部类类中方法外,static 修饰只能访问外部类静态成员,常配合 Builder 模式
局部内部类方法体内作用域仅限于方法内,可访问方法内 final / effectively final 变量
匿名内部类表达式(new 接口/抽象类)一次性使用,常用于事件监听。Lambda 表达式可简化 [JDK 8+]
// 匿名内部类 → Lambda 表达式简化
button.addActionListener(new ActionListener() {
    @Override public void actionPerformed(ActionEvent e) {
        System.out.println("clicked");
    }
});

// Lambda 等价写法 [JDK 8+]
button.addActionListener(e -> System.out.println("clicked"));

3.8 枚举(Enum)

[JDK 5+]

public enum Day {
    MONDAY("周一"), TUESDAY("周二"), WEDNESDAY("周三");

    private final String chineseName;

    Day(String name) { this.chineseName = name; }   // 枚举构造方法默认 private

    public String getChineseName() { return chineseName; }
}

Day today = Day.MONDAY;
System.out.println(today.name());         // "MONDAY"
System.out.println(today.ordinal());      // 0
System.out.println(today.getChineseName()); // "周一"
Day d = Day.valueOf("MONDAY");            // 字符串转枚举

所有枚举默认继承 java.lang.Enum,无法再继承其他类,但可实现接口。枚举天然是线程安全的单例。

3.9 记录类(Record)

[JDK 14 预览,JDK 16 正式]

// 自动生成:构造方法、equals()、hashCode()、toString()、getter(无 get 前缀)
public record Point(int x, int y) {
    // 紧凑构造方法(校验)
    public Point {
        if (x < 0 || y < 0) throw new IllegalArgumentException();
    }
    // 可添加实例方法
    public int distance() { return x + y; }
}

Point p = new Point(3, 4);
System.out.println(p.x());    // 3(访问器,方法名 = 字段名)
System.out.println(p);        // Point[x=3, y=4]

Record 是不可变数据载体,所有字段自动 private final,不能继承任何类(默认继承 java.lang.Record)。

3.10 本周实践任务

  • [ ] 设计一个继承体系(Animal → Dog/Cat),用多态统一调用 makeSound()
  • [ ] 对比 abstract class 和 interface 的设计选择场景
  • [ ] 用 record 替代传统 POJO,对比代码量
  • [ ] 实现一个函数式接口并用 Lambda 表达式传递行为
  • [ ] 验证 equals() 与 hashCode() 的契约:相等的对象必须有相等的 hashCode

第四阶段:异常处理

4.1 异常体系

类别特点示例
ErrorJVM 级严重错误,不应捕获OutOfMemoryError、StackOverflowError
受检异常(Checked)编译期强制 try-catch 或 throwsIOException、SQLException、ClassNotFoundException
运行时异常(Unchecked)编译期不检查,通常为编程错误NullPointerException、ArrayIndexOutOfBoundsException、IllegalArgumentException

4.2 异常处理语法

try {
    // 可能抛出异常的代码
    int result = 10 / 0;
} catch (ArithmeticException e) {
    System.err.println("算术异常: " + e.getMessage());
} catch (Exception e) {
    System.err.println("其他异常: " + e);
} finally {
    // 无论是否异常都会执行(资源释放)
    System.out.println("finally 块执行");
}

// try-with-resources [JDK 7+]:自动关闭资源
try (FileInputStream fis = new FileInputStream("file.txt");
     BufferedReader br = new BufferedReader(new InputStreamReader(fis))) {
    String line = br.readLine();
} catch (IOException e) {
    e.printStackTrace();
}
// 无需手动 close(),实现了 AutoCloseable 接口的资源会自动关闭

finally 的执行时机:除 System.exit(0) 或 JVM 崩溃外,finally 总会执行。即使 try/catch 中有 return,finally 也会在 return 之前执行。

异常处理原则:① 早抛出晚捕获;② 不要吞掉异常(空 catch 块);③ 抛出具体异常而不是泛化 Exception;④ finally 或 try-with-resources 确保资源释放。

4.3 本周实践任务

  • [ ] 验证 finally 在 return 之前的执行顺序
  • [ ] 用 try-with-resources 打开文件读写,对比传统的 try-catch-finally
  • [ ] 自定义异常类,区分业务异常 BusinessException 和系统异常 SystemException
  • [ ] 理解异常链(cause),用 throw new RuntimeException("包装", originalException) 保留根因

第五阶段:常用核心类

5.1 String 与 StringBuilder

类可变性线程安全性能适用场景
String不可变(final 类)✅ final 保证低(拼接时频繁创建对象)少量拼接、作为 Map key
StringBuilder可变❌ 非线程安全高单线程大量字符串拼接
StringBuffer可变✅ 线程安全(synchronized)中多线程字符串拼接
// String 不可变 —— 每次拼接都产生新对象
String s = "Hello";
s = s + " World";  // 创建新 String 对象

// String 常量池(字符串池)
String a = "abc";           // 字面量,指向常量池
String b = "abc";           // 指向同一常量池对象
String c = new String("abc"); // 强制在堆上创建新对象
System.out.println(a == b);  // true
System.out.println(a == c);  // false

// intern() 将堆上 String 放入常量池
System.out.println(a == c.intern()); // true

// StringBuilder 高效拼接
StringBuilder sb = new StringBuilder();
sb.append("Hello").append(" ").append("World");
String result = sb.toString();

// 文本块(Text Block)[JDK 13 预览,15 正式]
String json = """
    {
        "name": "Alice",
        "age": 20
    }
    """;

5.2 Object 类核心方法

所有 Java 类的根类是 java.lang.Object,核心方法:

方法说明
toString()返回对象字符串表示,默认返回 类名@哈希码
equals(Object)默认比较引用地址(==),需重写实现内容比较
hashCode()返回哈希码。重写 equals() 必须重写 hashCode()
clone()浅克隆。需实现 Cloneable 接口
getClass()返回运行时 Class 对象
finalize()垃圾回收前调用(JDK 9 起已废弃,不建议使用)
wait() / notify() / notifyAll()多线程同步(见并发章节)

5.3 包装类与 Math

// 包装类常量与方法
Integer.MAX_VALUE;           // 2147483647
Integer.parseInt("123");     // String → int
Integer.valueOf(100);        // int → Integer(使用缓存 -128 ~ 127)

// Math 工具
Math.abs(-5);                // 5
Math.max(3, 7);              // 7
Math.pow(2, 10);             // 1024.0
Math.sqrt(16);               // 4.0
Math.random();               // [0.0, 1.0) 随机数
Math.round(3.5);             // 4(四舍五入)
Math.floor(3.9);             // 3.0
Math.ceil(3.1);              // 4.0

5.4 新日期时间 API

[JDK 8+](java.time 包),替代旧的 java.util.Date 和 java.util.Calendar。

类说明
LocalDate日期(年-月-日)
LocalTime时间(时:分:秒)
LocalDateTime日期 + 时间
ZonedDateTime带时区的日期时间
Instant时间戳(自 1970-01-01T00:00:00Z)
Duration时间间隔(时分秒)
Period日期间隔(年月日)
DateTimeFormatter格式化器(线程安全,替代 SimpleDateFormat)
LocalDate today = LocalDate.now();
LocalDate birthday = LocalDate.of(2000, 1, 15);
Period age = Period.between(birthday, today);
long days = ChronoUnit.DAYS.between(birthday, today);

String formatted = LocalDateTime.now()
    .format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));

5.5 本周实践任务

  • [ ] 用 StringBuilder 拼接 10 万条字符串,对比 + 操作的时间差异
  • [ ] 理解 String 常量池:用 intern() 验证字符串池行为
  • [ ] 重写 equals() 和 hashCode(),测试 HashMap 存储时的一致性
  • [ ] 使用 LocalDate + Period 计算两个日期之间隔了多少个闰年
  • [ ] 用文本块(Text Block)编写 SQL 和 JSON 字符串,对比传统写法

第六阶段:泛型

[JDK 5+]

6.1 为什么使用泛型

泛型提供了编译期类型安全检查,避免 ClassCastException,同时消除强制类型转换。

// JDK 5 之前
List list = new ArrayList();
list.add("hello");
list.add(123);
String s = (String) list.get(0);  // 需要强制转换,容易出错

// JDK 5+ 泛型
List<String> list = new ArrayList<>();
list.add("hello");
// list.add(123);   ❌ 编译错误
String s = list.get(0);           // 无需强制转换

6.2 泛型类、接口、方法

// 泛型类
public class Box<T> {
    private T content;
    public T get() { return content; }
    public void set(T content) { this.content = content; }
}

// 泛型接口
public interface Repository<T, ID> {
    T findById(ID id);
    void save(T entity);
}

// 泛型方法
public static <T> T getFirst(List<T> list) {
    return list.isEmpty() ? null : list.get(0);
}

6.3 类型通配符与边界

语法含义适用场景
<?>无限定通配符仅读取,不依赖具体类型
<? extends T>上界通配符(T 及其子类)生产者(读取) —— PECS: Producer Extends
<? super T>下界通配符(T 及其父类)消费者(写入) —— PECS: Consumer Super
<T extends Comparable<T>>类型参数上界约束要求 T 实现 Comparable
// PECS 原则示例
public void copy(List<? extends Number> src, List<? super Number> dest) {
    for (Number n : src) {     // 安全读取(生产者 extends)
        dest.add(n);            // 安全写入(消费者 super)
    }
}

6.4 类型擦除

泛型信息仅在编译期存在,运行时会被擦除:

List<String> list1 = new ArrayList<>();
List<Integer> list2 = new ArrayList<>();
System.out.println(list1.getClass() == list2.getClass());  // true(都是 ArrayList.class)

类型擦除的后果:① 不能 instanceof 泛型类型(如 obj instanceof List<String> 编译错误);② 不能创建泛型数组(new T[5] 编译错误);③ 不能实例化类型参数(new T() 编译错误);④ 静态成员不能使用类的类型参数。

6.5 本周实践任务

  • [ ] 实现一个泛型工具方法:交换数组中任意两个位置的元素
  • [ ] 用 PECS 原则实现 copy 方法,理解 extends 和 super 的区别
  • [ ] 用反射验证类型擦除:获取 ArrayList<String> 和 ArrayList<Integer> 的 Class 对象比较
  • [ ] 理解泛型不能重载的场景:void method(List<String> list) 和 void method(List<Integer> list) 编译报错

第七阶段:集合框架

[JDK 1.2+](核心接口),[JDK 5+](泛型化)。这是面试和工作中最核心的数据结构知识。

7.1 集合框架总览

7.2 List

实现类底层结构随机访问增删(非尾部)线程安全适用场景
ArrayListObject[] 动态数组,扩容 1.5 倍O(1)O(n)❌频繁随机读取
LinkedList双向链表O(n)O(1)❌频繁头尾增删
VectorObject[] + synchronizedO(1)O(n)✅已过时,用 CopyOnWriteArrayList
CopyOnWriteArrayList写时复制数组O(1)O(n) 写✅读多写少
List<Integer> list = new ArrayList<>();
list.add(1);                    // 尾部追加
list.add(0, 0);                 // 指定位置插入
list.get(0);                    // 按索引访问
list.remove(0);                 // 按索引删除
list.remove(Integer.valueOf(1));// 按元素删除
list.contains(1);               // 是否包含
list.sort(Comparator.reverseOrder()); // 排序

// List 转数组
Integer[] arr = list.toArray(new Integer[0]);

ArrayList 扩容机制(高频面试考点):

  1. 默认初始容量 10
  2. 新增时若容量不足,扩容为原来的 1.5 倍(oldCapacity + (oldCapacity >> 1))
  3. 使用 Arrays.copyOf() 将原数组元素复制到新数组
  4. 可选:new ArrayList<>(预估容量) 减少扩容次数

7.3 Set

实现类底层结构有序性null适用场景
HashSetHashMap(key=元素, value=PRESENT 常量)无序✅ 1 个去重、快速查找
LinkedHashSetLinkedHashMap插入顺序✅ 1 个去重且保持插入顺序
TreeSetTreeMap(红黑树)自然序/Comparator❌有序集合、范围查找

Set 判断元素重复的依据是 hashCode() + equals()。存入 HashSet 的对象必须正确重写这两个方法。

7.4 Map

实现类底层结构有序性null 键null 值线程安全
HashMap数组+链表+红黑树(JDK 8+)无序✅ 1 个✅❌
LinkedHashMapHashMap + 双向链表插入/访问顺序✅ 1 个✅❌
TreeMap红黑树键自然序/Comparator❌✅❌
Hashtable数组+链表(加锁)无序❌❌✅
ConcurrentHashMap分段/节点锁 + CAS无序❌❌✅
Map<String, Integer> map = new HashMap<>();
map.put("Alice", 95);
map.get("Alice");               // 95
map.getOrDefault("Bob", 0);     // 不存在返回 0
map.containsKey("Alice");       // true
map.putIfAbsent("Alice", 100);  // 只有不存在时才放入
map.computeIfAbsent("Bob", k -> 0); // 不存在时计算放入
map.merge("Alice", 5, Integer::sum); // 合并值

// 遍历
map.forEach((k, v) -> System.out.println(k + " = " + v));
for (Map.Entry<String, Integer> entry : map.entrySet()) {
    System.out.println(entry.getKey() + " = " + entry.getValue());
}

HashMap 底层原理(高频面试考点):

  • JDK 7:数组 + 单向链表,头插法(并发下可能形成死循环)
  • JDK 8+:数组 + 单链表 + 红黑树(链表长度 ≥ 8 且数组长度 ≥ 64 时树化),尾插法
  • 默认初始容量 16,负载因子 0.75
  • 扩容为原来的 2 倍
  • hash() 方法:(h = key.hashCode()) ^ (h >>> 16)(高 16 位与低 16 位异或,减少碰撞)

7.5 Collections 工具类

Collections.sort(list);                // 排序(要求元素实现 Comparable)
Collections.sort(list, comparator);    // 自定义排序
Collections.reverse(list);             // 反转
Collections.shuffle(list);             // 随机打乱
Collections.max(list);                 // 最大值
Collections.min(list);                 // 最小值
Collections.binarySearch(list, key);   // 二分查找(前提:已排序)
Collections.synchronizedList(list);    // 包装为线程安全(性能差)
Collections.unmodifiableList(list);    // 包装为不可修改

List.of() / Set.of() / Map.of() [JDK 9+]:创建不可变集合。

List<String> list = List.of("a", "b", "c");    // 不可变,null 不允许
Map<String, Integer> map = Map.of("a", 1, "b", 2); // 最多 10 对键值

7.6 比较器

方式接口方法调用方式
自然排序Comparable<T>compareTo(T o)Collections.sort(list)
定制排序Comparator<T>compare(T o1, T o2)Collections.sort(list, comparator)
// Comparable:类内部定义自然顺序
public class Student implements Comparable<Student> {
    @Override public int compareTo(Student o) {
        return this.age - o.age;
    }
}

// Comparator:外部灵活定制(Lambda 简化)[JDK 8+]
students.sort(Comparator.comparing(Student::getAge)
        .thenComparing(Student::getName)
        .reversed());

7.7 Stream API

[JDK 8+] 函数式数据处理,链式操作,惰性求值。

List<String> names = students.stream()
    .filter(s -> s.getScore() >= 60)           // 过滤
    .sorted(Comparator.comparing(Student::getScore).reversed()) // 排序
    .skip(0).limit(10)                          // 分页
    .map(Student::getName)                      // 转换
    .collect(Collectors.toList());              // 收集

// 分组
Map<String, List<Student>> byGrade = students.stream()
    .collect(Collectors.groupingBy(s -> s.getScore() >= 60 ? "及格" : "不及格"));

// 规约
int total = students.stream()
    .mapToInt(Student::getScore).sum();

Optional<Student> top = students.stream()
    .max(Comparator.comparing(Student::getScore));

Stream 操作分类:

操作类型方法说明
中间操作(惰性)filter, map, flatMap, distinct, sorted, peek, limit, skip返回 Stream,不立即执行
终端操作(触发)collect, forEach, reduce, count, anyMatch, allMatch, findFirst返回结果或 void,触发流水线执行

7.8 本周实践任务

  • [ ] 对比 ArrayList 和 LinkedList 在头部插入 10 万条数据的耗时
  • [ ] 实现一个简单的 LRU 缓存(用 LinkedHashMap 的 accessOrder 模式)
  • [ ] 自定义类存入 HashSet,验证重写/不重写 hashCode() 和 equals() 时的行为差异
  • [ ] 用 Stream API 对 List 进行过滤、排序、分组、统计,对比传统 for 循环
  • [ ] 研究 HashMap 在 JDK 7 和 JDK 8+ 中的实现差异(头插法 vs 尾插法、红黑树引入原因)

第八阶段:I/O 流

8.1 I/O 流体系

Java I/O 基于装饰器模式,分为字节流和字符流两大类。

分类输入输出处理单位
字节流InputStreamOutputStream1 字节
字符流ReaderWriter1 字符(2 字节,自动编码)
缓冲流BufferedInputStream / BufferedReaderBufferedOutputStream / BufferedWriter缓冲提升性能
转换流InputStreamReaderOutputStreamWriter字节 → 字符 桥梁
// 字节流文件复制
try (FileInputStream fis = new FileInputStream("src.txt");
     FileOutputStream fos = new FileOutputStream("dest.txt")) {
    byte[] buffer = new byte[8192];
    int len;
    while ((len = fis.read(buffer)) != -1) {
        fos.write(buffer, 0, len);
    }
}

// 字符缓冲流逐行读取
try (BufferedReader br = new BufferedReader(new FileReader("file.txt"))) {
    String line;
    while ((line = br.readLine()) != null) {
        System.out.println(line);
    }
}

NIO(New I/O)引入的核心组件 [JDK 1.4+]:

组件说明
Channel(通道)双向数据传输,FileChannel、SocketChannel
Buffer(缓冲区)数据容器,ByteBuffer、CharBuffer
Selector(选择器)单线程管理多个 Channel,实现非阻塞 I/O

NIO.2(AIO) [JDK 7+]:

// Path 与 Files 工具(替代 File 类)
Path path = Paths.get("/tmp/test.txt");
List<String> lines = Files.readAllLines(path);                     // 一次性读所有行
Files.write(path, lines, StandardCharsets.UTF_8);                 // 一次性写入
Files.walk(Paths.get("/tmp"))                                      // 递归遍历文件树
    .filter(Files::isRegularFile)
    .forEach(System.out::println);

8.2 序列化

// 实现 Serializable 接口标记可序列化
public class User implements Serializable {
    private static final long serialVersionUID = 1L;  // 版本号
    private String name;
    private transient String password;  // transient 字段不参与序列化
}

// 序列化
try (ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("user.ser"))) {
    oos.writeObject(user);
}

// 反序列化(不调用构造方法)
try (ObjectInputStream ois = new ObjectInputStream(new FileInputStream("user.ser"))) {
    User user = (User) ois.readObject();
}

serialVersionUID 用于验证序列化兼容性。不显式声明时编译器自动生成,类修改后可能不兼容。

8.3 本周实践任务

  • [ ] 用字节流和字符流分别复制文件,对比性能和适用场景
  • [ ] 用 Files.walk() 统计某个目录下所有 .java 文件的总行数
  • [ ] 实现一个对象的序列化与反序列化,验证 transient 字段被跳过
  • [ ] 用 BufferedReader 读取大文件(>1GB),观察内存占用

第九阶段:多线程与并发

这是 Java 进阶的核心,也是企业级开发和面试的重中之重。

9.1 线程基础

// 方式一:继承 Thread
class MyThread extends Thread {
    @Override public void run() { System.out.println("子线程运行"); }
}
new MyThread().start();

// 方式二:实现 Runnable(推荐,解耦)
new Thread(() -> System.out.println("子线程运行")).start();

// 方式三:实现 Callable + Future(有返回值、可抛异常)
FutureTask<String> task = new FutureTask<>(() -> "结果");
new Thread(task).start();
String result = task.get();  // 阻塞等待结果

线程生命周期:

9.2 线程安全与锁

synchronized 关键字:

// 同步代码块
synchronized (lock) { ... }

// 同步实例方法(锁当前对象 this)
public synchronized void method() { ... }

// 同步静态方法(锁 Class 对象)
public static synchronized void staticMethod() { ... }

synchronized 在 JDK 6 后经过重大优化(偏向锁、轻量级锁、锁粗化、锁消除),性能已大幅提升。

Lock 接口 [JDK 5+](java.util.concurrent.locks):

特性synchronizedLock
可中断获取❌✅ lockInterruptibly()
尝试非阻塞获取❌✅ tryLock()
超时获取❌✅ tryLock(time, unit)
公平锁❌✅ new ReentrantLock(true)
条件变量wait/notify✅ Condition(多个等待队列)
自动释放✅(代码块结束或异常)❌ 必须 unlock()(finally 中)
ReentrantLock lock = new ReentrantLock();
try {
    lock.lock();
    // 临界区代码
} finally {
    lock.unlock();  // 务必在 finally 中释放
}

9.3 线程池

[JDK 5+] java.util.concurrent.ExecutorService

阿里巴巴开发手册强制要求:线程池必须通过 ThreadPoolExecutor 显式创建,禁止使用 Executors 工厂方法(newFixedThreadPool / newCachedThreadPool 可能导致 OOM)。

ThreadPoolExecutor executor = new ThreadPoolExecutor(
    4,                        // corePoolSize:核心线程数
    10,                       // maximumPoolSize:最大线程数
    60L, TimeUnit.SECONDS,    // keepAliveTime:空闲线程存活时间
    new LinkedBlockingQueue<>(100), // workQueue:任务队列
    new ThreadPoolExecutor.CallerRunsPolicy() // rejectedExecutionHandler:拒绝策略
);

// 提交任务
executor.execute(() -> { ... });           // Runnable,无返回值
Future<String> future = executor.submit(() -> "result");  // Callable,有返回值

// 优雅关闭
executor.shutdown();        // 不再接受新任务,等待已提交任务完成
executor.awaitTermination(60, TimeUnit.SECONDS);

拒绝策略:

策略行为
AbortPolicy(默认)抛 RejectedExecutionException
CallerRunsPolicy由调用者线程执行
DiscardPolicy静默丢弃
DiscardOldestPolicy丢弃队列中最旧任务

9.4 并发工具类

工具说明JDK
CountDownLatch等待 N 个线程完成5
CyclicBarrier所有线程到达屏障点后同时继续5
Semaphore控制同时访问资源的线程数(限流)5
Exchanger两个线程间交换数据5
// CountDownLatch 示例:主线程等待所有子任务完成
CountDownLatch latch = new CountDownLatch(5);
for (int i = 0; i < 5; i++) {
    new Thread(() -> {
        doWork();
        latch.countDown();
    }).start();
}
latch.await();  // 阻塞直到计数归零

9.5 并发集合

集合原理特点
ConcurrentHashMapJDK 7 分段锁;JDK 8 CAS + synchronized高并发读写,不锁整个 Map
CopyOnWriteArrayList写时复制整个数组读多写少,读无锁
BlockingQueue阻塞队列(生产者-消费者)ArrayBlockingQueue / LinkedBlockingQueue
// BlockingQueue 生产者-消费者模型
BlockingQueue<String> queue = new LinkedBlockingQueue<>(100);

// 生产者
queue.put(item);    // 队列满时阻塞

// 消费者
String item = queue.take(); // 队列空时阻塞

9.6 原子类与 CAS

[JDK 5+] java.util.concurrent.atomic

原子类对应类型
AtomicInteger / AtomicLong / AtomicBoolean基本类型
AtomicReference<T>引用类型
AtomicStampedReference<T>解决 ABA 问题(带版本号)
LongAdder / DoubleAdder高并发计数(比 AtomicLong 吞吐更高)[JDK 8+]
AtomicInteger counter = new AtomicInteger(0);
counter.incrementAndGet();     // 自增并返回(原子操作)
counter.compareAndSet(5, 10);  // CAS:期望值 5 时设置为 10

CAS(Compare And Swap)原理:无锁乐观算法,CPU 指令级原子操作。问题:① ABA 问题(用版本号解决);② 自旋开销;③ 只能保证一个共享变量的原子操作。

9.7 ThreadLocal

为每个线程提供独立的变量副本,实现线程隔离(如数据库连接、Session 管理、事务上下文)。

ThreadLocal<SimpleDateFormat> formatter = ThreadLocal.withInitial(
    () -> new SimpleDateFormat("yyyy-MM-dd")
);
String date = formatter.get().format(new Date());
// 使用后应在 finally 中 remove() 防止内存泄漏
formatter.remove();

ThreadLocal 的 key 是弱引用,但 value 是强引用。若 ThreadLocal 对象被 GC 但线程未销毁,value 无法被回收 → 内存泄漏。务必在 finally 中 remove()。

9.8 虚拟线程(Virtual Thread)

[JDK 19 预览,JDK 21 正式]

虚拟线程是轻量级用户态线程,由 JVM 调度而非 OS 调度,解决了平台线程数量限制和高并发下的线程切换开销问题。

// 创建虚拟线程
Thread vThread = Thread.ofVirtual().start(() -> {
    System.out.println("虚拟线程运行");
});

// 通过 ExecutorService 使用
try (ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor()) {
    executor.submit(() -> { ... });
    executor.submit(() -> { ... });
}
// try-with-resources 自动等待所有任务完成

虚拟线程特别适合 I/O 密集型、高并发场景,可与结构化并发 [JDK 21 预览] 配合使用。

9.9 本周实践任务

  • [ ] 用 ThreadPoolExecutor 手动创建线程池,模拟任务提交、队列满、拒绝策略触发
  • [ ] 用 CountDownLatch 实现并发测试:N 个线程同时执行,主线程等待全部完成后统计耗时
  • [ ] 实现生产者-消费者模式(BlockingQueue)
  • [ ] 对比 synchronized 和 ReentrantLock 在可中断获取锁时的行为差异
  • [ ] 体验虚拟线程:创建 100 万个虚拟线程执行 sleep 操作,观察内存占用

第十阶段:反射与注解

10.1 反射(Reflection)

反射是框架(Spring、MyBatis、JUnit)的核心基础。

// 获取 Class 对象的三种方式
Class<?> clazz1 = String.class;
Class<?> clazz2 = "hello".getClass();
Class<?> clazz3 = Class.forName("java.lang.String");  // 可能抛 ClassNotFoundException

// 创建实例
Object obj = clazz1.getDeclaredConstructor().newInstance();

// 获取方法并调用
Method method = clazz1.getMethod("length");
int length = (int) method.invoke("hello");

// 获取字段并修改
Field field = clazz1.getDeclaredField("value");  // String 的 value[]
field.setAccessible(true);  // 突破 private 限制
char[] value = (char[]) field.get("hello");

// 获取构造方法
Constructor<?> cons = clazz1.getConstructor(String.class);
String str = (String) cons.newInstance("hello");

反射的优缺点:灵活、动态性强(框架基础),但性能低、破坏封装、编译期安全检查失效。

10.2 注解(Annotation)

[JDK 5+],元数据标记。

内置注解:

注解作用
@Override标记方法重写,编译期检查
@Deprecated标记已过时,不推荐使用
@SuppressWarnings抑制编译器警告
@SafeVarargs抑制可变参数的堆污染警告
@FunctionalInterface标记函数式接口 [JDK 8+]

元注解(注解的注解):

元注解作用
@Target指定注解可用位置(TYPE/METHOD/FIELD/PARAMETER 等)
@Retention注解保留策略:SOURCE(源码) / CLASS(字节码) / RUNTIME(运行时)
@Documented被注解的元素会包含在 Javadoc 中
@Inherited子类可继承父类的该注解
@Repeatable允许在同一元素上重复使用 [JDK 8+]
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Log {
    String value() default "";
    boolean recordTime() default true;
}

// 使用注解
@Log(value = "用户登录", recordTime = true)
public void login() { ... }

注解 + 反射 → 框架基础:Spring 通过扫描 @Component、@Autowired 等注解,结合反射实现 IoC 和 DI。

10.3 本周实践任务

  • [ ] 用反射实现一个简单的 Bean 复制工具:遍历源对象字段,复制到目标对象同名字段
  • [ ] 自定义 @NotNull 和 @MaxLength 注解,用反射实现参数校验
  • [ ] 用 getDeclaredMethod("xxx") 调用私有方法,理解 setAccessible(true) 的作用
  • [ ] 对比反射创建对象与 new 创建对象的性能差异(循环 100 万次)

第十一阶段:JVM 基础

11.1 JVM 内存模型

区域存储内容线程共享GC异常
堆对象实例、数组✅✅ 主要 GC 区域OutOfMemoryError
元空间 [JDK 8+]类元信息、运行时常量池✅✅(Full GC 时)OutOfMemoryError
虚拟机栈局部变量表、操作数栈、方法出口❌❌StackOverflowError
程序计数器当前线程执行的字节码行号❌❌无
本地方法栈native 方法调用❌❌StackOverflowError

JDK 7 及以前为永久代(PermGen);JDK 8+ 替换为元空间(MetaSpace),使用本地内存,默认无上限,减少 Full GC。

11.2 垃圾回收(GC)

判断对象是否存活:

  • 引用计数法:无法解决循环引用(Java 不使用)
  • 可达性分析(Root Searching):从 GC Roots 出发,不可达的对象判定为可回收

GC Roots 包含:虚拟机栈引用对象、静态变量引用对象、常量池引用对象、JNI 引用对象。

垃圾回收算法:

算法原理优缺点
标记-清除标记存活对象 → 清除未标记产生内存碎片
标记-复制将存活对象复制到另一区域无碎片,但浪费一半内存(适合新生代)
标记-整理标记存活对象 → 移动到一端无碎片,但移动成本高(适合老年代)

分代收集理论:

新生代 → Minor GC(频繁,标记-复制算法)
  ├── Eden 区(新对象分配)
  ├── Survivor 0(From)
  └── Survivor 1(To)
       ↓ 对象熬过多次 Minor GC(默认 15 次)后晋升
老年代 → Major GC / Full GC(较少,标记-整理/清除算法)

常见垃圾回收器:

回收器算法特点适用
Serial标记-复制/整理单线程,STW 长客户端
Parallel标记-复制/整理多线程,吞吐量优先后台计算
CMS标记-清除并发、低延迟(已废弃 JDK 14)低延迟应用
G1分区 + 标记-整理可控停顿时间JDK 9+ 默认
ZGC [JDK 11+]染色指针超低停顿(<1ms)大堆低延迟
Shenandoah [JDK 12+]转发指针低停顿并发回收大堆低延迟

11.3 类加载机制

类加载器(双亲委派模型):

双亲委派机制:加载类时先从父加载器逐级向上查找,父加载器找到则返回,防止核心类被篡改。

11.4 本周实践任务

  • [ ] 用 -Xms 和 -Xmx 设置堆大小,用 jstat -gc 观察 GC 情况
  • [ ] 用 jmap -heap 查看堆内存分配,识别新生代和老年代
  • [ ] 制造 OOM 场景:不断 list.add(new byte[1024*1024]) 观察 GC 日志
  • [ ] 写一个自定义 ClassLoader,从指定路径加载 .class 文件
  • [ ] 对比不同垃圾回收器(Serial vs G1)在大量对象创建时的 GC 日志差异

第十二阶段:Java 新版本特性速览

版本核心特性影响力
Java 8Lambda、Stream、Optional、新日期 API、接口 default/static 方法⭐⭐⭐⭐⭐
Java 9模块化(Project Jigsaw)、List.of()、接口 private 方法、JShell⭐⭐⭐⭐
Java 10var 局部变量类型推断⭐⭐⭐
Java 11 (LTS)HTTP Client、String.isBlank() / lines() / strip()、直接运行 Java 文件⭐⭐⭐⭐
Java 14Switch 表达式(正式)、Records(预览)、instanceof 模式匹配(预览)、文本块(正式)⭐⭐⭐⭐
Java 16Records 正式、instanceof 模式匹配正式⭐⭐⭐⭐
Java 17 (LTS)Sealed Class、增强的伪随机数生成器⭐⭐⭐⭐
Java 21 (LTS)Virtual Thread、Record Pattern、Pattern Matching for switch 正式、SequencedCollection⭐⭐⭐⭐⭐
// Sealed Class [JDK 17+]
public sealed class Shape permits Circle, Rectangle, Triangle { }
public final class Circle extends Shape { }
// 限制哪些类可以继承 Shape,增强类型安全性

// Pattern Matching for switch [JDK 21 正式]
String result = switch (obj) {
    case Integer i -> "整数: " + i;
    case String s  -> "字符串: " + s;
    case null      -> "空值";
    default        -> "未知类型";
};

附录 A:Java SE 面试高频考点

  1. == 和 equals() 有什么区别?

    == 比较基本类型的值或引用类型的地址;equals() 比较对象内容(Object 默认用 ==,需重写)。String 的 equals() 已重写为内容比较。

  2. String、StringBuilder、StringBuffer 的区别?

    String 不可变,每次拼接产生新对象;StringBuilder 可变、非线程安全、性能最高;StringBuffer 可变、线程安全(synchronized)、性能次之。

  3. ArrayList 和 LinkedList 的区别?

    ArrayList 基于动态数组,随机访问 O(1),尾部增删 O(1),中间增删 O(n);LinkedList 基于双向链表,随机访问 O(n),头尾增删 O(1)。ArrayList 内存连续,LinkedList 额外存储前后指针。

  4. HashMap 的底层原理?

    JDK 8+:数组 + 链表 + 红黑树。通过 hash 确定桶位置,链表长度 ≥ 8 且数组长度 ≥ 64 时树化。默认容量 16,负载因子 0.75,扩容为 2 倍。

  5. HashMap 和 ConcurrentHashMap 的区别?

    HashMap 非线程安全;ConcurrentHashMap JDK 7 用分段锁,JDK 8 用 CAS + synchronized 锁单个桶节点,支持高并发读写。不允许 null 键和值。

  6. 重写(Override)和重载(Overload)的区别?

    重写:子类重新定义父类方法(签名相同),运行时多态。重载:同类中方法名相同但参数列表不同,编译期决定。

  7. 抽象类和接口的区别?Java 8+ 有什么变化?

    抽象类可以有构造方法和成员变量,单继承;接口不能有构造方法,变量只能是常量,可多实现。Java 8+ 接口支持 default 方法和 static 方法。

  8. 异常体系?Checked 和 Unchecked 的区别?

    Throwable → Error(不可处理)+ Exception。Exception → RuntimeException(非受检,编译不强制处理)+ 其他(受检,必须 try-catch 或 throws)。

  9. final、finally、finalize 的区别?

    final:修饰类不能继承、方法不能重写、变量不可变;finally:try-catch 后一定执行的代码块;finalize():GC 前调用的方法(JDK 9 废弃)。

  10. Java 的值传递和引用传递?

    Java 只有值传递。基本类型传值拷贝;引用类型传引用地址的拷贝(指向同一对象)。不可能通过方法参数修改外部引用的指向。

  11. 反射的原理和应用场景?

    运行时获取类信息(Class 对象),可创建实例、调用方法、修改字段。应用于框架(Spring IoC、MyBatis ORM)、动态代理、IDE 自动补全。

  12. 什么是 Java 的内存泄漏?常见场景?

    不再使用的对象无法被 GC 回收。常见场景:ThreadLocal 未 remove()、静态集合持有对象引用、未关闭的连接/流、内部类持有外部类引用。

  13. synchronized 和 Lock 的区别?

    synchronized 是 JVM 层面的关键字,自动释放锁;Lock 是 API 层面的接口(如 ReentrantLock),需手动释放,支持尝试获取、超时、可中断、公平锁。

  14. volatile 关键字的作用?

    ① 保证变量可见性(一个线程修改,其他线程立即可见);② 禁止指令重排序。但不能保证原子性(如 i++ 非原子)。

  15. 什么是 CAS?ABA 问题如何解决?

    CAS(Compare And Swap)是无锁乐观算法。ABA 问题:值从 A 变成 B 再变回 A,CAS 误认为未变化。用版本号(AtomicStampedReference)解决。

  16. ThreadLocal 的原理和内存泄漏问题?

    每个 Thread 有一个 ThreadLocalMap,key 为弱引用 ThreadLocal,value 为强引用值。ThreadLocal 被 GC 后 key 变 null,但 value 仍在 ThreadLocalMap 中(除非线程销毁或手动 remove)。

  17. JDK 动态代理和 CGLIB 代理的区别?

    JDK 动态代理要求目标类实现接口,生成 $Proxy 类;CGLIB 通过继承目标类生成子类,不能代理 final 类和方法。Spring AOP 会自动选择。


附录 B:核心 API 速查表

java.lang 包

类/接口说明
Object所有类的根类
String不可变字符序列
StringBuilder / StringBuffer可变字符序列
Integer / Long / Double / Boolean 等基本类型包装类
Math数学运算工具
Thread / Runnable线程
Throwable / Exception / Error异常体系
Class<T>类元信息(反射入口)
System系统工具(标准 I/O、GC、属性)
Enum枚举基类

java.util 包

类/接口说明
Collection / List / Set / Queue集合接口
Map键值对接口
ArrayList / LinkedListList 实现
HashSet / TreeSet / LinkedHashSetSet 实现
HashMap / TreeMap / LinkedHashMapMap 实现
Collections集合工具类
Arrays数组工具类
Comparator / Comparable比较器接口
Optional [JDK 8+]空值安全包装
Objects [JDK 7+]对象工具(空安全 equals/hash)
Random / ThreadLocalRandom随机数

java.util.concurrent 包 [JDK 5+]

类/接口说明
ExecutorService / ThreadPoolExecutor线程池
ConcurrentHashMap并发 Map
CopyOnWriteArrayList写时复制 List
BlockingQueue / ArrayBlockingQueue阻塞队列
CountDownLatch / CyclicBarrier同步工具
Semaphore信号量
AtomicInteger / AtomicReference原子类
ReentrantLock可重入锁
CompletableFuture [JDK 8+]异步编排

java.io / java.nio 包

类说明
File / Path [JDK 7+]文件路径
InputStream / OutputStream字节流
Reader / Writer字符流
BufferedReader / BufferedWriter缓冲字符流
ObjectInputStream / ObjectOutputStream序列化
Files [JDK 7+]文件工具(NIO.2)

java.time 包 [JDK 8+]

类说明
LocalDate / LocalTime / LocalDateTime日期时间
Instant时间戳
Duration / Period时间间隔
DateTimeFormatter格式化器

java.util.stream 包 [JDK 8+]

类说明
Stream<T>数据流操作
Collectors收集器(toList、groupingBy 等)
IntStream / LongStream / DoubleStream数值流

附录 C:学习资源与工具

  • Oracle 官方教程:https://docs.oracle.com/javase/tutorial/
  • Java SE 规范:https://docs.oracle.com/javase/specs/
  • JDK 发行说明:https://www.oracle.com/java/technologies/javase/jdk-relnotes-index.html
  • OpenJDK:https://openjdk.org/
  • IntelliJ IDEA:Java 开发首选 IDE(社区版免费)
  • VisualVM / JConsole:JVM 监控工具
  • Arthas:阿里巴巴开源的 Java 诊断工具
  • JMH(Java Microbenchmark Harness):微基准测试框架

版本说明:本教程以 Java SE 8 为基线,标记 [JDK x+] 的新特性表示自该版本起可用。当前最新 LTS 为 Java 21(2023.09),建议学习和项目开发使用 Java 17 或 21。

下一页
Java SE 专业术语