|
|
@@ -0,0 +1,276 @@
|
|
|
+# 阶段七:JVM 类加载与反射 —— 核心知识点总纲
|
|
|
+
|
|
|
+> 本阶段涵盖:**类加载机制与反射、反射 Field 字段反射与 Method 方法反射**
|
|
|
+> 细分文档:`按日细分/20260812-笔记.md`、`按日细分/20260813-笔记.md`
|
|
|
+> 学生需要重点理解、背诵、掌握的理论核心知识点。
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+## 一、类加载机制(对应 08-12)
|
|
|
+
|
|
|
+### 1. Java 程序执行全流程(必背总纲)
|
|
|
+
|
|
|
+```
|
|
|
+.java 源文件 --编译--> .class 字节码 --类加载器--> 内存 --> JVM 解释 --> 二进制机器码 --> 执行
|
|
|
+```
|
|
|
+
|
|
|
+- **`.class` 字节码平台无关** → Java 跨平台原理
|
|
|
+- **类加载器** = 字节码的"搬运工"(把 .class / jar 包加载进内存)
|
|
|
+
|
|
|
+### 2. 类加载的 6 种时机(必背)
|
|
|
+
|
|
|
+| # | 触发场景 | 示例 |
|
|
|
+|---|----------|------|
|
|
|
+| ① | 创建类的实例对象 | `new Demo01()` |
|
|
|
+| ② | 调用 static 方法 | `Math.abs(-1)` |
|
|
|
+| ③ | 访问/赋值 static 变量 | `Student.school = "..."` |
|
|
|
+| ④ | 反射创建 Class 对象 | `Class.forName("...")` |
|
|
|
+| ⑤ | 初始化子类(先加载父类) | `new SubStudent()` |
|
|
|
+| ⑥ | Java.exe 运行主类 | `java course.Demo01` |
|
|
|
+
|
|
|
+> **懒加载原则**:使用时才加载。初始化子类**先触发父类加载**(先父后子)。
|
|
|
+
|
|
|
+### 3. 类的加载过程(3 大步 5 小步,必背)
|
|
|
+
|
|
|
+```
|
|
|
+1. 加载(Loading):通过全限定名获取字节流 → 生成 java.lang.Class 对象
|
|
|
+2. 链接(Linking)
|
|
|
+ ├── 验证(Verify):检查字节流符合规范、无安全隐患
|
|
|
+ ├── 准备(Prepare):为 static 变量分配内存并设默认值(int→0)
|
|
|
+ └── 解析(Resolve):符号引用 → 直接引用;用到其他类在此查找
|
|
|
+3. 初始化(Initialization):执行静态变量赋值、静态代码块
|
|
|
+```
|
|
|
+
|
|
|
+**一句话**:加载"搬文件"、验证"查安全"、准备"分默认内存"、解析"找引用的类"、初始化"跑初始化代码"。
|
|
|
+
|
|
|
+### 4. 执行顺序(必背)
|
|
|
+
|
|
|
+**静态代码块(类加载初始化阶段,只执行一次)→ 普通代码块(每次 new,构造前)→ 构造方法**
|
|
|
+
|
|
|
+### 5. 三种类加载器(必背)
|
|
|
+
|
|
|
+| 类加载器 | 职责 | 父加载器 |
|
|
|
+|----------|------|----------|
|
|
|
+| BootstrapClassLoader(启动) | 最核心 JDK 类 | 无(表示为 null) |
|
|
|
+| PlatformClassLoader(平台) | JDK 特殊模块 | Bootstrap |
|
|
|
+| SystemClassLoader(系统) | **用户类路径的类** | Platform |
|
|
|
+
|
|
|
+- **BootstrapClassLoader 由 C/C++ 实现,Java 中表示为 null**;对 null 调 getParent() 空指针
|
|
|
+- 获取:`ClassLoader.getSystemClassLoader()` → 逐级 `getParent()`
|
|
|
+
|
|
|
+### 6. 双亲委派模型(必背)
|
|
|
+
|
|
|
+**概念**:类加载器收到加载请求**不自己先加载**,先委派给父加载器,递归到最顶层;顶层能加载就成功,顶层不行才由子加载器尝试。
|
|
|
+- **委派向上**(子→父→最顶层);**回退向下**(顶层→子)
|
|
|
+- 核心类(java.lang.String)由顶层加载;用户类由系统类加载器加载
|
|
|
+
|
|
|
+**为什么需要双亲委派(三原因必背):**
|
|
|
+1. **避免类被重复加载**:同一类全 JVM 只有一个 Class 对象(唯一性 = 类 + 类加载器共同决定)
|
|
|
+2. **保证核心类库安全**:用户写的假 `java.lang.String` 永远不会被加载
|
|
|
+3. **保证类的唯一性**:避免多份 String 类型混乱
|
|
|
+
|
|
|
+### 7. 类加载器加载配置文件(getResourceAsStream + Properties)
|
|
|
+
|
|
|
+```java
|
|
|
+ClassLoader cl = ClassLoader.getSystemClassLoader();
|
|
|
+InputStream in = cl.getResourceAsStream("prop.properties"); // classpath 根目录
|
|
|
+Properties pro = new Properties();
|
|
|
+pro.load(in);
|
|
|
+String driver = pro.getProperty("db.driver");
|
|
|
+in.close();
|
|
|
+```
|
|
|
+
|
|
|
+- **Properties**:父类 Hashtable、Map 实现类;`load()` 加载、`getProperty(key)` 取值
|
|
|
+- 意义:**配置与代码分离**(改配置不用改代码);DB 四要素 driver/url/username/password
|
|
|
+
|
|
|
+## 二、反射机制(对应 08-12)
|
|
|
+
|
|
|
+### 1. 概念(必背)
|
|
|
+
|
|
|
+**反射是 Java 的运行时动态机制**:运行状态中能获取任意类的所有属性方法(**包括 private**)、调用任意对象的任意属性和方法。反射是 Spring/MyBatis/Hibernate/JDBC 等**框架的基础**。
|
|
|
+
|
|
|
+### 2. 普通调用 vs 反射调用(5 维对比必背)
|
|
|
+
|
|
|
+| 维度 | 普通调用 | 反射调用 |
|
|
|
+|------|---------|---------|
|
|
|
+| 获取信息时机 | 编译期写死 | **运行时动态** |
|
|
|
+| 依赖关系 | 强耦合 | **解耦** |
|
|
|
+| 创建对象 | `new 类名()` | `Class.forName() + newInstance()` |
|
|
|
+| 调用方法 | `对象.方法()` | `method.invoke(对象, 参数)` |
|
|
|
+| 灵活性 | 固定 | 高度灵活 |
|
|
|
+
|
|
|
+### 3. 反射的注意事项(必背)
|
|
|
+
|
|
|
+**日常业务开发尽量不用反射**(像开挂):①**可能破坏封装性**(能拿 private)②**效率低**(比正常创建低 3~100 倍)。
|
|
|
+> 学习反射的目的:理解框架底层源码 + 架构/中间件做解耦适配。
|
|
|
+
|
|
|
+### 4. 反射工作机制(必背链条)
|
|
|
+
|
|
|
+```
|
|
|
+Person.java → javac → Person.class → 类加载器 → Class 对象(类的类模板)
|
|
|
+ ├── Constructor → newInstance() 创建对象
|
|
|
+ ├── Field → get/set 读写字段
|
|
|
+ └── Method → invoke() 执行方法
|
|
|
+```
|
|
|
+
|
|
|
+### 5. 反射核心类
|
|
|
+
|
|
|
+Class(反射入口)/ Constructor(创建对象)/ Field(读写字段)/ Method(调用方法)/ Modifier(解析修饰符)/ Parameter(方法参数)
|
|
|
+
|
|
|
+### 6. 获取 Class 对象的三种方式(必背)
|
|
|
+
|
|
|
+| 方式 | 写法 | 特点 |
|
|
|
+|------|------|------|
|
|
|
+| 方式一 | `Student.class` | 最直接,编译期类型检查 |
|
|
|
+| 方式二 | `student.getClass()` | Object 方法,需有对象 |
|
|
|
+| 方式三 | `Class.forName("course.Student")` | 字符串传类名**最灵活**,**框架最常用**;写错抛 ClassNotFoundException |
|
|
|
+
|
|
|
+**三个重要验证:**
|
|
|
+1. **殊途同归**:三种方式拿到**同一个对象**(clazz1 == clazz2 == clazz3 全 true)
|
|
|
+2. **基本类型和数组也有 Class 对象**:`int.class == Integer.TYPE`
|
|
|
+3. **类加载时机差异**:`Class.forName()` **会触发静态代码块**;`类名.class` 和 `对象.getClass()` 不触发
|
|
|
+
|
|
|
+**查看类型信息:** `getName()`(全类名)/ `getSimpleName()` / `getSuperclass()` / `getPackage()`
|
|
|
+
|
|
|
+### 7. 反射 Constructor(构造方法)
|
|
|
+
|
|
|
+**4 个获取 API:**
|
|
|
+
|
|
|
+| 方法 | 是否含 private |
|
|
|
+|------|---------------|
|
|
|
+| `getConstructors()` | ❌ 只 public |
|
|
|
+| `getConstructor(Class...)` | ❌ 只 public |
|
|
|
+| `getDeclaredConstructors()` | ✅ 含私有 |
|
|
|
+| `getDeclaredConstructor(Class...)` | ✅ 含私有 |
|
|
|
+
|
|
|
+**暴力反射:** 私有构造直接 `newInstance()` 报权限错,先 **`setAccessible(true)`** 放开权限。
|
|
|
+
|
|
|
+```java
|
|
|
+Constructor<?> dc = studentClass.getDeclaredConstructor(String.class, Integer.class);
|
|
|
+dc.setAccessible(true);
|
|
|
+Object o = dc.newInstance("张三", 1001);
|
|
|
+```
|
|
|
+
|
|
|
+**反射受检异常:** ClassNotFoundException / NoSuchMethodException / InstantiationException / IllegalAccessException / InvocationTargetException
|
|
|
+
|
|
|
+## 三、反射 Field 字段反射(对应 08-13)
|
|
|
+
|
|
|
+### 1. Field 概述
|
|
|
+
|
|
|
+**Field 对象代表类中的一个成员变量。** `get()` 读、`set()` 写。
|
|
|
+> 框架典型应用:ORM 框架把数据库数据映射到 Java 类,**用的就是 Field.set()**(ORM 底层原理)。
|
|
|
+
|
|
|
+### 2. 获取 Field 的 4 个 API(必背)
|
|
|
+
|
|
|
+| 方法 | 含 private | 含父类继承 |
|
|
|
+|------|-----------|-----------|
|
|
|
+| `getFields()` | ❌ | ✅ |
|
|
|
+| `getField(name)` | ❌ | ✅ |
|
|
|
+| `getDeclaredFields()` | ✅ 本类全部 | ❌ |
|
|
|
+| `getDeclaredField(name)` | ✅ | ❌ |
|
|
|
+
|
|
|
+### 3. Field 常用方法(必背)
|
|
|
+
|
|
|
+`get(obj)` 读值 / `set(obj, 值)` 赋值 / `setAccessible(true)` 暴力反射 / `getType()` 类型 / `getName()` 属性名 / `getModifiers()` 修饰符(int,`Modifier.toString()` 解析)
|
|
|
+
|
|
|
+### 4. 操作静态属性(对象参数传 null,必背)
|
|
|
+
|
|
|
+| 场景 | get 参数 | set 参数 | 原因 |
|
|
|
+|------|---------|---------|------|
|
|
|
+| 实例属性 | `get(对象)` | `set(对象, 值)` | 属于某个对象 |
|
|
|
+| **静态属性** | `get(null)` | `set(null, 值)` | **属于整个类** |
|
|
|
+
|
|
|
+### 5. 四个典型操作
|
|
|
+
|
|
|
+```java
|
|
|
+// ① 遍历所有属性,输出修饰符+类型+属性名
|
|
|
+Field[] fields = clazz.getDeclaredFields();
|
|
|
+for (Field f : fields) {
|
|
|
+ System.out.println(Modifier.toString(f.getModifiers()) + " " + f.getType().getSimpleName() + " " + f.getName());
|
|
|
+}
|
|
|
+// ② 操作 public 字段
|
|
|
+Field emailField = clazz.getField("email");
|
|
|
+emailField.get(s); emailField.set(s, "lisi@qq.com");
|
|
|
+// ③ 操作 private 字段(暴力反射)
|
|
|
+Field nameField = clazz.getDeclaredField("name");
|
|
|
+nameField.setAccessible(true); nameField.get(s); nameField.set(s, "李四");
|
|
|
+// ④ 操作 static 字段(传 null)
|
|
|
+Field schoolField = clazz.getDeclaredField("school");
|
|
|
+schoolField.get(null); schoolField.set(null, "新学校");
|
|
|
+```
|
|
|
+
|
|
|
+## 四、反射 Method 方法反射(对应 08-13)
|
|
|
+
|
|
|
+### 1. Method 概述
|
|
|
+
|
|
|
+**Method 对象代表类中的一个方法。** 反射通过 `Method.invoke(对象, 参数...)` 调用方法,**等价于 `对象.方法(参数)`**——方法名称和参数**运行时才确定**。
|
|
|
+> 应用:动态代理、测试框架(JUnit)、注解解释器、框架调用 setter/getter。
|
|
|
+
|
|
|
+### 2. 获取 Method 的 4 个 API(必背)
|
|
|
+
|
|
|
+| 方法 | 含 private | 含父类/接口继承 |
|
|
|
+|------|-----------|-----------------|
|
|
|
+| `getMethods()` | ❌ | ✅(含 toString/hashCode) |
|
|
|
+| `getMethod(name, parameterTypes)` | ❌ | ✅ |
|
|
|
+| `getDeclaredMethods()` | ✅ 本类全部 | ❌ |
|
|
|
+| `getDeclaredMethod(name, parameterTypes)` | ✅ | ❌ |
|
|
|
+
|
|
|
+**重载方法必须指明参数类型(必背):**
|
|
|
+
|
|
|
+```java
|
|
|
+getMethod("setName", String.class) // String.class 用来区分同名重载
|
|
|
+```
|
|
|
+
|
|
|
+> 不写或写错参数类型都抛 `NoSuchMethodException`。
|
|
|
+
|
|
|
+### 3. Method 常用方法(必背)
|
|
|
+
|
|
|
+`invoke(obj, args)` 调用 / `setAccessible(true)` 暴力反射 / `getReturnType()` 返回值类型 / `getParameterTypes()` 参数类型数组 / `getModifiers()` 修饰符
|
|
|
+
|
|
|
+### 4. invoke 的四种调用规律(重点必背)
|
|
|
+
|
|
|
+| 方法类型 | invoke 写法 |
|
|
|
+|----------|-------------|
|
|
|
+| public 实例方法 | `invoke(对象, 参数...)` |
|
|
|
+| **static 静态方法** | `invoke(null, 参数...)` |
|
|
|
+| **void 无返回值方法** | 调用后返回 **null** |
|
|
|
+| **private 私有方法** | 先 `setAccessible(true)` 再 invoke |
|
|
|
+
|
|
|
+## 五、反射知识全景总览(四类知识地图,必背)
|
|
|
+
|
|
|
+### 12 个获取 API 的统一规律(3 组 × 4 个)
|
|
|
+
|
|
|
+| 成员 | 取多个(数组) | 取单个 | 含私有数组 | 含私有单个 |
|
|
|
+|------|---------------|--------|-----------|-----------|
|
|
|
+| 属性 | `getFields()` | `getField(name)` | `getDeclaredFields()` | `getDeclaredField(name)` |
|
|
|
+| 方法 | `getMethods()` | `getMethod(name, 参数类型...)` | `getDeclaredMethods()` | `getDeclaredMethod(name, 参数类型...)` |
|
|
|
+| 构造 | `getConstructors()` | `getConstructor(参数类型...)` | `getDeclaredConstructors()` | `getDeclaredConstructor(参数类型...)` |
|
|
|
+
|
|
|
+> **口诀(贯穿三组)**:**含 `Declared` 的能拿私有(本类全部),不含 `Declared` 的只能拿 public(含父类/接口继承)。**
|
|
|
+
|
|
|
+### 每类反射对象的关键方法
|
|
|
+
|
|
|
+| 类别 | 关注点 | 关键方法 |
|
|
|
+|------|--------|----------|
|
|
|
+| Field 属性 | 属性组成部分 | 名字 getName、修饰符 getModifiers、**值 get/set** |
|
|
|
+| Method 方法 | 方法组成部分 | 名字 getName、**执行 invoke**、返回值 getReturnType、参数 getParameterTypes、修饰符 getModifiers |
|
|
|
+| Constructor 构造 | 构造组成部分 | 修饰符 getModifiers、参数 getParameterTypes、**创建 newInstance** |
|
|
|
+
|
|
|
+### 反射三大成员统一套路(必背)
|
|
|
+
|
|
|
+**`getDeclaredXxx` 拿私有 + `setAccessible(true)` 放开权限 + 执行操作**(Constructor→newInstance / Field→get/set / Method→invoke);**操作静态成员(属性/方法)对象参数传 null。**
|
|
|
+
|
|
|
+## 本阶段必须背诵的核心口诀
|
|
|
+
|
|
|
+1. **类加载 6 时机 + 懒加载原则**
|
|
|
+2. **加载 → 链接(验证/准备/解析)→ 初始化**(3 大步 5 小步)
|
|
|
+3. **静态代码块 → 代码块 → 构造方法**
|
|
|
+4. **三种类加载器**:系统 → 平台 → 启动(null)
|
|
|
+5. **双亲委派**:委派向上、回退向下;三原因(避免重复加载/核心类安全/保证唯一性)
|
|
|
+6. **反射 = 运行时动态获取类信息 + 动态调用**;从 Class 对象出发(Constructor/Field/Method)
|
|
|
+7. **三种获取 Class**:类名.class / 对象.getClass() / Class.forName()(最灵活、触发静态块)
|
|
|
+8. **Declared 口诀**:含 Declared 拿私有,不含只拿 public
|
|
|
+9. **setAccessible(true) = 暴力反射**(访问私有成员的关键一步)
|
|
|
+10. **invoke 四规律**:实例传对象、静态传 null、void 返回 null、private 先 setAccessible
|
|
|
+11. **反射三件套**:Constructor 建对象 + Field 读写字段 + Method 调用方法
|
|
|
+12. **操作静态成员传 null**(属性/方法统一规律)
|