|
|
@@ -4,7 +4,7 @@
|
|
|
- **项目**:`c260813`
|
|
|
- **包路径**:`course`
|
|
|
- **作者**:WanJL
|
|
|
-- **内容概览**:反射 Field(属性/字段/变量)(Demo01 演示:Class 类获取 Field 对象的 4 个 API → 获取所有属性并输出修饰符和类型 → 读取/修改 public 属性 → setAccessible(true) 暴力反射读取/修改 private 属性 → 操作静态属性传 null)+ 反射 Method(方法)(Demo02 演示:Class 类获取 Method 对象的 4 个 API → 遍历方法输出方法名/参数/返回值 → invoke 调用实例方法/带参方法/私有方法/静态方法)+ Student 实体类(private/public/public static 字段设计 + 4 个构造方法 + 7 组 getter/setter + 私有方法 read/write)
|
|
|
+- **内容概览**:反射 Field(属性/字段/变量)(Demo01 演示:Class 类获取 Field 对象的 4 个 API → 获取所有属性并输出修饰符和类型 → 读取/修改 public 属性 → setAccessible(true) 暴力反射读取/修改 private 属性 → 操作静态属性传 null)+ 反射 Method(方法)(Demo02 演示:Class 类获取 Method 对象的 4 个 API → 遍历方法输出方法名/参数/返回值 → invoke 调用实例方法/带参方法/私有方法/静态方法)+ 反射知识全景总览(Demo03:把整个反射体系整理成 4 类知识地图——Class 类反射(成员属性/方法/构造)、Field 属性反射、Method 方法反射、Constructor 构造反射)+ Student 实体类(private/public/public static 字段设计 + 4 个构造方法 + 7 组 getter/setter + 私有方法 read/write)
|
|
|
|
|
|
---
|
|
|
|
|
|
@@ -22,9 +22,10 @@
|
|
|
10. [获取 Method 对象的 4 个 API:Declared 与重载参数](#10-获取-method-对象的-4-个-apideclared-与重载参数)
|
|
|
11. [Method 类的常用方法:invoke/setAccessible/getReturnType/getParameterTypes/getModifiers](#11-method-类的常用方法invokesetaccessiblegetreturntypegetparametertypesgetmodifiers)
|
|
|
12. [Demo02 演示:遍历方法 + invoke 调用实例/带参/私有/静态方法](#12-demo02-演示遍历方法-invoke-调用实例带参私有静态方法)
|
|
|
-13. [知识点全景总结](#13-知识点全景总结)
|
|
|
-14. [随堂练习要点](#14-随堂练习要点)
|
|
|
-15. [拓展阅读](#15-拓展阅读)
|
|
|
+13. [反射知识全景总览(Demo03):四类反射的完整知识地图](#13-反射知识全景总览demo03四类反射的完整知识地图)
|
|
|
+14. [知识点全景总结](#14-知识点全景总结)
|
|
|
+15. [随堂练习要点](#15-随堂练习要点)
|
|
|
+16. [拓展阅读](#16-拓展阅读)
|
|
|
|
|
|
---
|
|
|
|
|
|
@@ -709,7 +710,87 @@ getSchool() 返回值=String
|
|
|
|
|
|
---
|
|
|
|
|
|
-## 13. 知识点全景总结
|
|
|
+## 13. 反射知识全景总览(Demo03):四类反射的完整知识地图
|
|
|
+
|
|
|
+### 概念 —— 把整个反射体系整理成 4 类知识地图
|
|
|
+
|
|
|
+学完了反射的三大核心成员(Constructor / Field / Method)+ 获取 Class 对象后,Demo03 用一段类注释把**整个反射知识体系整理成 4 类全景地图**——它是"反射到底有哪些 API"的**总索引**:先分清"针对哪一类做反射"(Class/Field/Method/Constructor),再记住"每一类反射关注什么、有哪些方法"。**Demo03 没有 main 方法,它就是一张纯知识点的知识地图**。
|
|
|
+
|
|
|
+```java
|
|
|
+// 来源:course/Demo03.java(类注释)
|
|
|
+/*
|
|
|
+ 如果想要弄明白反射,需要掌握以下内容:
|
|
|
+ 1、针对类的反射--Class-就需要记住类里面有哪些成员?
|
|
|
+ |- 成员属性
|
|
|
+ |- 获取一个对象:getField()
|
|
|
+ |- 获取多个对象(数组):getFields()
|
|
|
+ |- 获取一个私有对象:getDeclaredField()
|
|
|
+ |- 获取多个私有对象:getDeclaredFields()
|
|
|
+ |- 成员方法
|
|
|
+ |- 获取对象:getMethod()
|
|
|
+ |- 获取多个对象(数组):getMethods()
|
|
|
+ |- 获取一个私有对象:getDeclaredMethod()
|
|
|
+ |- 获取多个私有对象:getDeclaredMethods()
|
|
|
+ |- 构造方法
|
|
|
+ |- 获得对象:getConstructor()
|
|
|
+ |- 获取多个对象(数组):getConstructors()
|
|
|
+ |- 获取一个私有对象:getDeclaredConstructor()
|
|
|
+ |- 获取多个私有对象:getDeclaredConstructors()
|
|
|
+ 2、针对属性的反射--Field-就需要记住属性的组成部分有哪些?
|
|
|
+ |- 属性变量名 getName()
|
|
|
+ |- 属性修饰符 getModifiers()
|
|
|
+ |- 属性值
|
|
|
+ |- 获取值 get()
|
|
|
+ |- 赋值 set()
|
|
|
+ 3、针对方法的反射--Method-就需要记住方法的组成部分有哪些?
|
|
|
+ |- 方法名称 getName()
|
|
|
+ |- 执行方法 invoke()
|
|
|
+ |- 方法返回值类型 getReturnType()
|
|
|
+ |- 方法的参数列表类型 getParameterTypes()
|
|
|
+ |- 方法的修饰符 getModifiers()
|
|
|
+ 4、针对构造放过的反射--Constructor--就需要记住构造方法的组成部分有哪些?
|
|
|
+ |- 构造方法的修饰符 getModifiers()
|
|
|
+ |- 构造方法的参数列表类型 getParameterTypes()
|
|
|
+ |- 创建对象 newInstance()
|
|
|
+*/
|
|
|
+```
|
|
|
+
|
|
|
+### 四类反射知识地图
|
|
|
+
|
|
|
+| 反射类别 | 关注点 | 获取对象的 API(4 个/类) | 对象自身的常用方法 |
|
|
|
+|----------|--------|--------------------------|---------------------|
|
|
|
+| **① Class 类反射** | 类里面有哪些**成员**(属性/方法/构造) | 属性:`getField`/`getFields`/`getDeclaredField`/`getDeclaredFields`;方法:`getMethod`/`getMethods`/`getDeclaredMethod`/`getDeclaredMethods`;构造:`getConstructor`/`getConstructors`/`getDeclaredConstructor`/`getDeclaredConstructors` | — |
|
|
|
+| **② Field 属性反射** | 属性的**组成部分**(名字/修饰符/值) | 获取方式见 Class 反射 | 属性名 `getName()`、修饰符 `getModifiers()`、**值 `get()` / `set()`** |
|
|
|
+| **③ Method 方法反射** | 方法的**组成部分**(名字/执行/返回值/参数/修饰符) | 获取方式见 Class 反射 | 方法名 `getName()`、**执行 `invoke()`**、返回值类型 `getReturnType()`、参数类型 `getParameterTypes()`、修饰符 `getModifiers()` |
|
|
|
+| **④ Constructor 构造反射** | 构造方法的**组成部分**(修饰符/参数/创建对象) | 获取方式见 Class 反射 | 修饰符 `getModifiers()`、参数类型 `getParameterTypes()`、**创建对象 `newInstance()`** |
|
|
|
+
|
|
|
+### 记忆要点:三组 12 个获取 API + 每类对象的关键方法
|
|
|
+
|
|
|
+**① 获取 API 的规律(3 组 × 4 个 = 12 个)**:每个成员(属性/方法/构造)都有**同样的 4 个获取方法**:
|
|
|
+
|
|
|
+| 成员 | 取多个(数组) | 取单个 | 取多个含私有 | 取单个含私有 |
|
|
|
+|------|---------------|--------|--------------|--------------|
|
|
|
+| 属性 | `getFields()` | `getField(name)` | `getDeclaredFields()` | `getDeclaredField(name)` |
|
|
|
+| 方法 | `getMethods()` | `getMethod(name, 参数类型...)` | `getDeclaredMethods()` | `getDeclaredMethod(name, 参数类型...)` |
|
|
|
+| 构造 | `getConstructors()` | `getConstructor(参数类型...)` | `getDeclaredConstructors()` | `getDeclaredConstructor(参数类型...)` |
|
|
|
+
|
|
|
+> **记忆口诀**:**含 `Declared` 的能拿私有(本类全部),不含 `Declared` 的只能拿 public(含父类/接口继承)**——三组获取 API 共用同一条口诀
|
|
|
+
|
|
|
+**② 每类反射对象的关键方法**:
|
|
|
+
|
|
|
+- **Field 看"属性值"**:属性有三部分——名字 `getName()`、修饰符 `getModifiers()`、**值 `get()` / `set()`**
|
|
|
+- **Method 看"执行"**:方法有五部分——名字 `getName()`、**执行 `invoke()`**、返回值类型 `getReturnType()`、参数类型 `getParameterTypes()`、修饰符 `getModifiers()`
|
|
|
+- **Constructor 看"创建"**:构造方法有三部分——修饰符 `getModifiers()`、参数类型 `getParameterTypes()`、**创建对象 `newInstance()`**
|
|
|
+- **三个反射对象共有的 API**:Field/Method/Constructor 都有 `getModifiers()`(返回 int,`Modifier.toString()` 解析)和 `getParameterTypes()`(Constructor/Method 有参数,Field 无参数)
|
|
|
+
|
|
|
+> **要点**:
|
|
|
+> - **反射的总纲**:先"拿 Class"→ 再"按成员类型拿反射对象"(Field/Method/Constructor)→ 最后"用反射对象操作成员"(get/set / invoke / newInstance)——Demo03 把这条路整理成了知识地图
|
|
|
+> - **12 个获取 API 有统一规律**:每个成员都是"4 个获取方法",只是前缀从 Field/Method/Constructor 换一下——记住一个就记住全部
|
|
|
+> - **本章"作业答案参考"**:练习五答案 `exericse/MethodPrintUtilTest.java`(遍历方法时用了 `setAccessible(true)` 暴力反射 + `Modifier.toString` + 字符串修复去掉方括号)、练习六答案 `exericse/MethodInvokeTest.java`(`invokeMethod` 通用工具用 `args[i].getClass()` **动态计算参数类型数组**)
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+## 14. 知识点全景总结
|
|
|
|
|
|
| 知识点 | 核心内容 | 来源 |
|
|
|
|--------|----------|------|
|
|
|
@@ -754,10 +835,18 @@ getSchool() 返回值=String
|
|
|
| **演示:暴力反射私有方法** | `getDeclaredMethod("read")` + `setAccessible(true)` + `invoke(s)` 调用 private 实例方法;`getDeclaredMethod("write")` + `setAccessible(true)` + `invoke(null)` 调用 private 静态方法(传 null) | course/Demo02 main |
|
|
|
| **反射三大成员统一套路** | Constructor(newInstance 创建对象)/ Field(get/set 读写字段)/ Method(invoke 调用方法)——**Declared 拿私有 + setAccessible(true) 放开权限**,操作静态成员(属性/方法)传 null | course/Demo01 + Demo02 |
|
|
|
| **受检异常** | Demo01 main throws `ClassNotFoundException, NoSuchFieldException, IllegalAccessException`(Field);Demo02 main throws `NoSuchMethodException, InvocationTargetException, IllegalAccessException`(Method)——方法名/参数类型不匹配抛 NoSuchMethodException、被调方法内部抛异常时 invoke 抛 InvocationTargetException | course/Demo01 + Demo02 main |
|
|
|
+| **反射知识全景总览(Demo03)** | 把整个反射体系整理成 4 类知识地图:①Class 类反射(类里的成员——属性/方法/构造)②Field 属性反射(属性的组成部分)③Method 方法反射(方法的组成部分)④Constructor 构造反射(构造方法的组成部分)——Demo03 没有 main 方法,是纯知识点类 | course/Demo03 注释 |
|
|
|
+| **12 个获取 API 的统一规律** | 属性/方法/构造各有 4 个获取方法(数组/单个/含私有数组/含私有单个)——`getXxx(s)` / `getDeclaredXxx(s)`,口诀"含 Declared 的能拿私有"统一适用于三组 | course/Demo03 注释 |
|
|
|
+| **Field 属性三部分组成** | 属性变量名 `getName()` / 属性修饰符 `getModifiers()` / 属性值 `get()` + `set()` | course/Demo03 注释 |
|
|
|
+| **Method 方法五部分组成** | 方法名称 `getName()` / 执行方法 `invoke()` / 返回值类型 `getReturnType()` / 参数列表类型 `getParameterTypes()` / 修饰符 `getModifiers()` | course/Demo03 注释 |
|
|
|
+| **Constructor 构造三部分组成** | 构造方法修饰符 `getModifiers()` / 参数列表类型 `getParameterTypes()` / 创建对象 `newInstance()` | course/Demo03 注释 |
|
|
|
+| **练习五答案参考** | `exericse/MethodPrintUtilTest.java`——printDeclaredMethods 遍历时用 `setAccessible(true)` 暴力反射 + `Modifier.toString` 解析修饰符 + **字符串修复**(replace 去掉参数类型 List 的 `[` `]` 方括号) | exericse/MethodPrintUtilTest.java |
|
|
|
+| **练习六答案参考** | `exericse/MethodInvokeTest.java`——invokeMethod 通用工具用 **`args[i].getClass()` 动态计算参数类型数组**(不写死参数类型),再 `getMethod(methodName, classes)` + `invoke(obj, args)`;无参数与有参数两种分支处理 | exericse/MethodInvokeTest.java |
|
|
|
+| **exericse/Student 实体类** | 练习包 `exericse` 的实体类:private(id/name/age)+ public static(school)+ 新增 getter/setter + `eat(String s)` 方法(打印"吃:s")——练习五/六的反射目标 | exericse/Student.java |
|
|
|
|
|
|
---
|
|
|
|
|
|
-## 14. 随堂练习要点
|
|
|
+## 15. 随堂练习要点
|
|
|
|
|
|
- **Field 概念复述(必做)**:用一句话说清"什么是 Field 反射"——Field 对象代表类中的一个成员变量,反射通过 `get()` 读取字段值、`set()` 修改字段值;能说出框架中的应用(ORM 框架查询数据库后用 Field.set() 把数据映射到 Java 类)
|
|
|
- **获取 Field 的 4 个 API 背诵(必做)**:`getFields()`(所有 public 数组,含父类继承)/ `getField(String name)`(指定 public)/ `getDeclaredFields()`(本类全部含 private,不含父类)/ `getDeclaredField(String name)`(指定含 private)——背口诀:**含 Declared 的能拿私有(本类全部),不含 Declared 的只能拿 public(含父类继承)**
|
|
|
@@ -786,10 +875,17 @@ getSchool() 返回值=String
|
|
|
- **getMethods vs getDeclaredMethods 对比**:思考两者的区别——getMethods 拿 public + 父类/接口继承;getDeclaredMethods 拿本类全部(含 private)不含父类。数一数 Student 的 getMethods() 输出里有哪些是 Object 继承来的(toString/hashCode/equals/getClass/notify/wait 等)
|
|
|
- **InvocationTargetException 理解**:把 `read()` 方法体内故意写一个会抛异常的语句(如 `int x = 1/0`),反射 `invoke` 调用它,观察抛 **InvocationTargetException**(被调方法内部异常被包装)——回顾 07-28 异常处理知识
|
|
|
- **练习答案参考**:课堂练习四(模拟 ORM mapToObject)的参考答案代码在 `exericse/OrmFieldMapTest.java`(含 `exericse/Student.java` 实体类)——运行观察静态字段传 null 操作 + Map 数据库行映射到 Student 对象的完整流程
|
|
|
+- **反射知识全景背诵(必做)**:把 Demo03 的 4 类知识地图背下来——①Class 类反射(成员属性/方法/构造)②Field 属性反射(名字/修饰符/值)③Method 方法反射(名字/执行/返回值/参数/修饰符)④Constructor 构造反射(修饰符/参数/创建对象)——能不看笔记默写出来
|
|
|
+- **12 个获取 API 默写(必做)**:给"属性/方法/构造"各自默写 4 个获取方法(数组/单个/含私有数组/含私有单个)——`getFields`/`getField`/`getDeclaredFields`/`getDeclaredField`(属性)、`getMethods`/`getMethod`/`getDeclaredMethods`/`getDeclaredMethod`(方法)、`getConstructors`/`getConstructor`/`getDeclaredConstructors`/`getDeclaredConstructor`(构造)——体会"三组 12 个 API 规律完全一致"
|
|
|
+- **口诀统一性验证**:对照 12 个获取 API,逐个确认"含 Declared 的能拿私有、不含 Declared 的只能拿 public"对属性/方法/构造三组都成立——这是反射 API 的统一规律
|
|
|
+- **反射对象共有 API 对比(必做)**:列出 Field/Method/Constructor 三者**共同有的方法**(`getModifiers()` 修饰符 + `getName()`),以及各自**独有的方法**(Field:get/set;Method:invoke/getReturnType/getParameterTypes;Constructor:newInstance/getParameterTypes)——画一张对比表
|
|
|
+- **练习五答案参考**:`exericse/MethodPrintUtilTest.java`——printDeclaredMethods 遍历时对每个方法 `setAccessible(true)` + `Modifier.toString` 解析修饰符 + 字符串修复(replace 去掉参数类型 List 的 `[` `]`);运行观察输出 `private void write()` 这类带修饰符的方法行
|
|
|
+- **练习六答案参考**:`exericse/MethodInvokeTest.java`——`invokeMethod` 通用工具用 `args[i].getClass()` **动态计算参数类型数组**(不需要写死 String.class),并区分"有参数/无参数"两个分支;main 里调用 `invokeMethod(s, "eat", "饭...")` 调用 exericse/Student 新增的 `eat(String)` 方法
|
|
|
+- **Demo03 无 main 方法理解**:观察 Demo03 类只有大段注释没有 main 方法——体会"注释也能承载知识点":反射知识地图以注释形式存在,需要时打开 Demo03.java 即可总览全部反射 API
|
|
|
|
|
|
---
|
|
|
|
|
|
-## 15. 拓展阅读
|
|
|
+## 16. 拓展阅读
|
|
|
|
|
|
- **反射 Field 在 ORM 框架中的落地**:MyBatis、Hibernate 等 ORM 框架的**结果映射(Result Mapping)**就是本课"Field.set() 把数据库数据映射到 Java 类"的经典实现——数据库表字段名对应 Java 实体属性名,查询结果通过反射 Field.set() 逐字段赋值
|
|
|
- **反射三大核心成员(已全部学完)**:反射三大核心成员已全部掌握——**Constructor(构造方法,08-12 newInstance 创建对象)+ Field(字段属性,本课 get/set 读写字段)+ Method(方法,本课 invoke 调用方法)**——三者套路完全一致:`getDeclaredXxx` 拿私有 + `setAccessible(true)` 放开权限 + 执行操作;至此反射三件套(建对象/读写属性/调方法)可组合完成框架级操作
|
|
|
@@ -809,5 +905,9 @@ getSchool() 返回值=String
|
|
|
- **IDEA 调试器的实现原理**:IDEA 等 IDE 的**调试器变量查看窗口**能在运行时显示对象的所有字段值(包括 private)——底层就是反射 `getDeclaredFields()` + `setAccessible(true)` + `field.get(对象)`,与本课 Demo01 的演示逻辑一致
|
|
|
- **JSON 序列化框架**:Jackson / Gson / Fastjson 把 Java 对象转成 JSON 字符串、或把 JSON 转回对象,底层也大量使用 Field 反射——读取对象所有字段名与值(序列化)、按 JSON 键名给对象字段赋值(反序列化)
|
|
|
- **反射破坏封装性的辩证关系**:本课 Field 反射可以访问 private 字段、修改 final 字段,既是框架能力的来源,也是"破坏封装性"的体现——日常业务代码中应遵守上一课的原则:**正常业务用普通方式访问属性,反射留给框架与中间件**
|
|
|
-- **JDK 文档**:[`java.lang.Class`](https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/lang/Class.html)(getFields/getField/getDeclaredFields/getDeclaredField + getMethods/getMethod/getDeclaredMethods/getDeclaredMethod)、[`java.lang.reflect.Field`](https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/lang/reflect/Field.html)(get/set/setAccessible/getType/getName/getModifiers)、[`java.lang.reflect.Method`](https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/lang/reflect/Method.html)(invoke/setAccessible/getReturnType/getParameterTypes/getModifiers)、[`java.lang.reflect.Modifier`](https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/lang/reflect/Modifier.html)(toString/isPublic/isStatic 等修饰符解析工具类)
|
|
|
+- **反射 API 的"总索引"价值**:Demo03 的类注释相当于一张**反射 API 速查表**——面试或写框架代码时"忘了某个 API 名字",打开 Demo03.java 就能看到 4 类反射的全部方法(Class 的 12 个获取方法 + Field/Method/Constructor 各自的组成部分方法);这种"用注释承载知识地图"的做法也适合自己整理学习笔记
|
|
|
+- **12 个获取 API 与"组合拳"思维**:反射 3 个成员(Field/Method/Constructor)× 4 种获取方式(数组/单个/含私有数组/含私有单个)= 12 个 API,规律完全一致——记住"每个成员 4 个获取方法 + Declared 口诀"就能举一反三,这也是面试常考的"反射 API 全家桶"
|
|
|
+- **Constructor 反射的补充方法**:Demo03 提到 Constructor 也有 `getModifiers()`(构造修饰符)和 `getParameterTypes()`(构造参数类型)——上一课(08-12)主要用了 `newInstance()` 创建对象,这两个方法是构造反射的补充维度,可在练习中试用(打印构造方法的修饰符与参数类型)
|
|
|
+- **练习答案中的通用工具设计**:练习五答案用"遍历 + setAccessible + Modifier.toString + 字符串修复"打印方法信息、练习六答案用"`args[i].getClass()` 动态计算参数类型"实现通用 invoke——这两种技巧(字符串清理、动态参数类型推导)是写反射通用工具的常用套路,后续做框架级工具时可直接复用
|
|
|
+- **JDK 文档**:[`java.lang.Class`](https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/lang/Class.html)(getFields/getField/getDeclaredFields/getDeclaredField + getMethods/getMethod/getDeclaredMethods/getDeclaredMethod + getConstructors/getConstructor/getDeclaredConstructors/getDeclaredConstructor)、[`java.lang.reflect.Field`](https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/lang/reflect/Field.html)(get/set/setAccessible/getType/getName/getModifiers)、[`java.lang.reflect.Method`](https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/lang/reflect/Method.html)(invoke/setAccessible/getReturnType/getParameterTypes/getModifiers)、[`java.lang.reflect.Constructor`](https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/lang/reflect/Constructor.html)(newInstance/setAccessible/getModifiers/getParameterTypes)、[`java.lang.reflect.Modifier`](https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/lang/reflect/Modifier.html)(toString/isPublic/isStatic 等修饰符解析工具类)
|
|
|
|