|
@@ -0,0 +1,126 @@
|
|
|
|
|
+# 2026年8月12日 课后作业 — 反射:遍历 SysUser 四个构造方法创建对象
|
|
|
|
|
+
|
|
|
|
|
+> **说明**:本次课程学习了 **反射机制(Reflection)**(Demo04:反射概念、普通调用 vs 反射调用、为什么需要反射、反射核心类)、**获取 Class 对象三种方式**(Demo05:类名.class / 对象.getClass() / Class.forName("全类名"),同一个类三种方式拿到同一个对象)、**反射 Constructor 构造方法**(Demo06:getConstructors / getConstructor / getDeclaredConstructors / getDeclaredConstructor 获取构造方法、setAccessible(true) 暴力反射、newInstance() 反射创建对象、instanceof 判断 + 强转调用方法)。
|
|
|
|
|
+>
|
|
|
|
|
+> 本作业共 **1 道题(必做)**:用反射分别通过 **SysUser 的 4 个构造方法**(public 无参 / private 二参 / public 六参 / private 四参)创建对象——覆盖"拿 Class → 拿构造 → 建对象"的反射创建对象完整流程,重点练习 **getDeclaredConstructor + setAccessible(true) 暴力反射**访问私有构造方法。
|
|
|
|
|
+
|
|
|
|
|
+---
|
|
|
|
|
+
|
|
|
|
|
+## 📌 作业总体要求
|
|
|
|
|
+
|
|
|
|
|
+### 一、命名要求
|
|
|
|
|
+
|
|
|
|
|
+| 项目 | 要求 |
|
|
|
|
|
+|------|------|
|
|
|
|
|
+| **类名** | `Demo_01_你的姓名`(如 `Demo_01_张三`) |
|
|
|
|
|
+| **文件头注释** | Java 文件头部需包含 `@author`、`@title`、`@create` 文档注释 |
|
|
|
|
|
+| **实体类** | 使用课程代码中的 `course.SysUser` 实体类(`授课代码/c260812/src/course/SysUser.java`) |
|
|
|
|
|
+
|
|
|
|
|
+### 二、提交方式与截止时间
|
|
|
|
|
+
|
|
|
|
|
+| 项目 | 要求 |
|
|
|
|
|
+|------|------|
|
|
|
|
|
+| **提交方式** | 将源码文件 + 运行结果截图提交至班级指定平台 |
|
|
|
|
|
+| **截止时间** | 下次上课前 |
|
|
|
|
|
+
|
|
|
|
|
+---
|
|
|
|
|
+
|
|
|
|
|
+## 一、基础题(必做)
|
|
|
|
|
+
|
|
|
|
|
+### 题目 1:反射遍历 SysUser 四个构造方法创建对象(⭐⭐⭐ 必做)
|
|
|
|
|
+
|
|
|
|
|
+**知识点**:`Class.forName("全类名")` 获取 Class 对象、`getConstructors()` / `getDeclaredConstructors()` 获取构造方法数组、`getConstructor(参数类型...)` / `getDeclaredConstructor(参数类型...)` 获取指定构造方法、`newInstance()` 反射创建对象、`setAccessible(true)` 暴力反射访问私有构造、`instanceof` 判断类型、向下转型、调用 toString()
|
|
|
|
|
+
|
|
|
|
|
+**场景描述**:课堂学了**反射最核心的用途**——拿到 Class 对象后,通过构造方法创建对象(这是 Spring IOC 等框架的底层原理)。`SysUser` 系统用户类一共有 **4 个构造方法**(2 个 public + 2 个 private):
|
|
|
|
|
+
|
|
|
|
|
+```java
|
|
|
|
|
+// SysUser 的 4 个构造方法(源码:course/SysUser.java)
|
|
|
|
|
+public SysUser() // ① public 无参
|
|
|
|
|
+private SysUser(String username, String password) // ② private 二参(用户名,密码)
|
|
|
|
|
+public SysUser(String id, String username, String password,
|
|
|
|
|
+ String name, String phone, String email) // ③ public 六参(完整用户信息)
|
|
|
|
|
+private SysUser(String id, String name,
|
|
|
|
|
+ String phone, String email) // ④ private 四参(基础信息)
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+请用反射**分别通过这 4 个构造方法创建 4 个 SysUser 对象**——完整走一遍"拿 Class → 拿构造 → 建对象"的反射创建对象流程,并重点体会:**private 构造方法必须用 `getDeclaredConstructor` + `setAccessible(true)` 暴力反射**才能调用。
|
|
|
|
|
+
|
|
|
|
|
+**题目要求**:
|
|
|
|
|
+
|
|
|
|
|
+```java
|
|
|
|
|
+/**
|
|
|
|
|
+ * @author 你的姓名
|
|
|
|
|
+ * @title 题目1:反射遍历 SysUser 四个构造方法创建对象
|
|
|
|
|
+ * @create 2026/8/12
|
|
|
|
|
+ */
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+**实现步骤**:
|
|
|
|
|
+
|
|
|
|
|
+1. `Class.forName("course.SysUser")` 获取 SysUser 的 Class 对象
|
|
|
|
|
+2. `getConstructors()` 统计 public 构造个数(2 个),`getDeclaredConstructors()` 统计全部构造个数(4 个,含 private)
|
|
|
|
|
+3. **反射创建对象①**:`getConstructor()` 获取 public 无参构造 → `newInstance()` 创建空对象
|
|
|
|
|
+4. **反射创建对象②**:`getConstructor(String.class × 6)` 获取 public 六参构造 → `newInstance(id, username, password, name, phone, email)` 创建完整用户对象
|
|
|
|
|
+5. **反射创建对象③**:`getDeclaredConstructor(String.class, String.class)` 获取 private 二参构造 → `setAccessible(true)` → `newInstance("admin", "admin888")` 暴力反射创建对象
|
|
|
|
|
+6. **反射创建对象④**:`getDeclaredConstructor(String.class × 4)` 获取 private 四参构造 → `setAccessible(true)` → `newInstance(id, name, phone, email)` 暴力反射创建对象
|
|
|
|
|
+7. 每个对象 `instanceof SysUser` 判断 + 打印 `toString()` 验证属性
|
|
|
|
|
+
|
|
|
|
|
+**代码框架**:
|
|
|
|
|
+
|
|
|
|
|
+```java
|
|
|
|
|
+package course;
|
|
|
|
|
+
|
|
|
|
|
+import java.lang.reflect.Constructor;
|
|
|
|
|
+
|
|
|
|
|
+public class Demo_01_你的姓名 {
|
|
|
|
|
+ public static void main(String[] args) throws Exception {
|
|
|
|
|
+ // 1. 用 Class.forName 获取 SysUser 的 Class 对象
|
|
|
|
|
+ // 2. 分别打印 public 构造个数和全部构造个数
|
|
|
|
|
+ // 3. 用 public 无参构造反射创建对象①,并 instanceof 判断
|
|
|
|
|
+ // 4. 用 public 六参构造反射创建对象②
|
|
|
|
|
+ // 5. 用 private 二参构造反射创建对象③(需放开访问权限)
|
|
|
|
|
+ // 6. 用 private 四参构造反射创建对象④(需放开访问权限)
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+**输出示例**:
|
|
|
|
|
+
|
|
|
|
|
+```
|
|
|
|
|
+public 构造方法个数:2
|
|
|
|
|
+全部构造方法个数(含private):4
|
|
|
|
|
+① 无参构造:SysUser{id='null', username='null', password='null', name='null', phone='null', email='null'}(是SysUser吗?true)
|
|
|
|
|
+② 六参构造:SysUser{id='1', username='zhangsan', password='123456', name='张三', phone='13800000000', email='zhangsan@qq.com'}
|
|
|
|
|
+③ 私有二参构造:SysUser{id='null', username='admin', password='admin888', name='null', phone='null', email='null'}
|
|
|
|
|
+④ 私有四参构造:SysUser{id='2', username='null', password='null', name='李四', phone='13900000000', email='lisi@qq.com'}
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+**选做加分**:
|
|
|
|
|
+
|
|
|
|
|
+- **暴力反射对比实验**:把对象③/④的 `setAccessible(true)` 注释掉再运行,观察抛 **IllegalAccessException**——体会"私有构造必须放开访问权限"
|
|
|
|
|
+- **Declared 口诀验证**:用 `getConstructor(String.class, String.class)`(不带 Declared)尝试获取 private 二参构造,观察抛 **NoSuchMethodException**——验证"不含 Declared 只能拿 public"
|
|
|
|
|
+- **遍历构造方法**:`for (Constructor<?> c : clazz.getDeclaredConstructors())` 打印每个构造的 `getParameterCount()`(参数个数)和 `getParameterTypes()`(参数类型),观察 4 个构造的参数差异
|
|
|
|
|
+- 分别用三种方式获取 Class 对象(`SysUser.class` / `new SysUser().getClass()` / `Class.forName("course.SysUser")`),打印三个对象是否相等(`==` 结果应为 true)
|
|
|
|
|
+
|
|
|
|
|
+**思考题**(将答案写在代码文件头注释或提交报告里):
|
|
|
|
|
+
|
|
|
|
|
+1. SysUser 有 2 个 private 构造方法,为什么 `getConstructor()` 拿不到它们?必须用什么方法组合?(提示:`getDeclaredConstructor` + `setAccessible(true)`,口诀"含 Declared 的才能拿私有")
|
|
|
|
|
+2. public 构造和 private 构造,反射创建对象的方式有什么不同?多出来的 `setAccessible(true)` 做了什么?
|
|
|
|
|
+3. 反射创建的对象是 `Object` 类型,怎么确认它确实是 SysUser?确认后如何调用 SysUser 的方法?(提示:`instanceof` + 强转)
|
|
|
|
|
+
|
|
|
|
|
+---
|
|
|
|
|
+
|
|
|
|
|
+# 涵盖知识点总览
|
|
|
|
|
+
|
|
|
|
|
+| 知识点 | 说明 |
|
|
|
|
|
+|--------|------|
|
|
|
|
|
+| `Class.forName("全类名")` | 方式三获取 Class 对象:字符串传类名、最灵活、框架最常用;全类名写错抛 ClassNotFoundException |
|
|
|
|
|
+| 获取 Class 对象三种方式 | ①类名.class(编译期类型检查最安全)②对象.getClass()(需有对象实例)③Class.forName(最灵活)——同一个类三种方式拿到同一个对象 |
|
|
|
|
|
+| `getConstructors()` / `getDeclaredConstructors()` | 分别获取 public 构造数组 / 全部构造数组(含 private)——SysUser 对应 2 个和 4 个 |
|
|
|
|
|
+| `getConstructor()` / `newInstance()` | 获取 public 无参构造 + 反射创建对象(对应普通 `new 类名()`) |
|
|
|
|
|
+| `getConstructor(参数类型...)` | 获取指定参数类型的 public 构造方法,`newInstance(参数...)` 创建带属性对象 |
|
|
|
|
|
+| `getDeclaredConstructor(参数类型...)` | 获取指定参数类型的构造方法(**含 private**),需配合 `setAccessible(true)` |
|
|
|
|
|
+| `setAccessible(true)` 暴力反射 | 放开私有成员的访问权限,否则调用 private 构造的 `newInstance()` 会抛 IllegalAccessException |
|
|
|
|
|
+| `newInstance()` | 反射创建对象;public 构造直接调用,private 构造需先 `setAccessible(true)` |
|
|
|
|
|
+| instanceof + 向下转型 | 反射创建的对象是 Object 类型,`instanceof SysUser` 判断后强转再调用方法 |
|
|
|
|
|
+| 反射 API 的受检异常 | ClassNotFoundException / NoSuchMethodException / InstantiationException / IllegalAccessException / InvocationTargetException——必须处理(main 用 throws) |
|