Java学习29
·
一、上午 3h:反射入门 + 获取 Class 字节码对象
1. 反射概念与作用(0.5h)
什么是反射?
反射:Java 程序运行时,可以动态获取任意类的完整结构(构造方法、成员变量、成员方法),并且可以动态创建对象、调用方法、操作属性的机制。
核心特点
- 动态性:不用提前写死代码,运行时才确定操作哪个类、哪个方法
- 破封装:可以访问
private私有成员(普通代码无法直接访问) - 框架基石:Spring、MyBatis、SpringBoot 底层全是反射,没有反射就没有主流 Java 框架
反射适用场景
- 框架底层(自动注入、对象创建)
- 配置文件解析(通过字符串全类名创建对象)
- 动态代理、单元测试
- 通用工具类开发
2. 类的生命周期与 Class 对象(0.5h)
类的生命周期
.java 源文件 → 编译 → .class 字节码文件 → JVM 加载 → 生成唯一 Class 对象 → 创建实例对象
Class 对象是什么?
- 每个类被加载到 JVM 后,只会生成一个唯一的 Class 字节码对象
- Class 对象中封装了当前类的所有信息:包名、类名、父类、接口、构造、变量、方法
- 反射的所有操作,都必须从 Class 对象开始
3. 获取 Class 类三种方式(重点必背 2h)
三种方式(必须背熟)
- 类名.class:编译期确定,最简单
- 对象.getClass ():通过已有对象获取
- Class.forName ("全类名"):运行时动态加载,框架最常用
完整代码示例 + 逐行解释
我们先创建一个实体类Student,后续所有反射案例都用这个类:
java
运行
// 实体类:用于反射测试
public class Student {
// 私有成员变量
private String name;
public int age;
// 无参构造
public Student() {}
// 有参构造
public Student(String name, int age) {
this.name = name;
this.age = age;
}
// 公有方法
public void study() {
System.out.println("学生正在学习");
}
// 私有方法
private void sleep() {
System.out.println("学生正在睡觉");
}
// getter/setter
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public int getAge() { return age; }
public void setAge(int age) { this.age = age; }
@Override
public String toString() {
return "Student{name='" + name + "', age=" + age + "}";
}
}
获取Class对象的完整代码:
java
运行
public class GetClassObject {
public static void main(String[] args) throws ClassNotFoundException {
// 方式1:类名.class 编译期确定,最常用
Class<Student> c1 = Student.class;
System.out.println("方式1:" + c1);
// 方式2:对象.getClass() 必须先有对象
Student student = new Student();
Class<? extends Student> c2 = student.getClass();
System.out.println("方式2:" + c2);
// 方式3:Class.forName("全类名") 运行时动态加载,框架核心
Class<?> c3 = Class.forName("com.example.Student"); // 包名+类名
System.out.println("方式3:" + c3);
// 重点:三个对象是同一个!证明一个类只有一个Class对象
System.out.println(c1 == c2); // true
System.out.println(c1 == c3); // true
}
}
代码解释
c1:直接通过类获取,最安全、性能最高c2:必须先创建对象,才能获取 Class,不适合框架c3:最常用,传入字符串全类名,运行时加载类,Spring/MyBatis 都用它- 三个对象地址相同,证明一个类只有一个 Class 对象
二、下午 2.5h:反射获取类成员并操作
1. 反射获取构造方法(0.8h)
核心 API
getConstructor(Class...):获取公有构造方法getDeclaredConstructor(Class...):获取任意构造(含私有)newInstance():通过构造创建对象setAccessible(true):暴力反射,破封装
完整代码示例
java
运行
import java.lang.reflect.Constructor;
public class ReflectConstructor {
public static void main(String[] args) throws Exception {
// 1. 获取Class对象
Class<?> clazz = Class.forName("com.example.Student");
// ====================== 1. 获取无参公有构造 ======================
Constructor<?> con1 = clazz.getConstructor();
Object obj1 = con1.newInstance(); // 创建对象
System.out.println("无参构造创建:" + obj1);
// ====================== 2. 获取有参公有构造 ======================
Constructor<?> con2 = clazz.getConstructor(String.class, int.class);
Object obj2 = con2.newInstance("张三", 20);
System.out.println("有参构造创建:" + obj2);
// ====================== 3. 暴力反射获取私有构造(补充) ======================
// 假如Student有private Student(String name){}
// Constructor<?> con3 = clazz.getDeclaredConstructor(String.class);
// con3.setAccessible(true); // 破封装
// Object obj3 = con3.newInstance("李四");
}
}
核心知识点
- 无参构造是框架创建对象的默认方式
setAccessible(true):关闭访问检查,允许访问私有成员- 反射创建对象的本质:不使用
new关键字创建对象
2. 反射获取成员变量(0.8h)
核心 API
getField(String name):获取公有成员变量getDeclaredField(String name):获取任意变量(含私有)set(Object obj, value):给对象赋值get(Object obj):获取对象的值setAccessible(true):破私有
完整代码示例
java
运行
import java.lang.reflect.Field;
public class ReflectField {
public static void main(String[] args) throws Exception {
Class<?> clazz = Class.forName("com.example.Student");
Object obj = clazz.newInstance(); // 先创建对象
// ====================== 1. 操作公有变量 age ======================
Field ageField = clazz.getField("age");
ageField.set(obj, 18); // 赋值
int age = (int) ageField.get(obj); // 取值
System.out.println("公有age:" + age);
// ====================== 2. 操作私有变量 name ======================
Field nameField = clazz.getDeclaredField("name");
nameField.setAccessible(true); // 破封装
nameField.set(obj, "反射赋值"); // 给私有变量赋值
String name = (String) nameField.get(obj); // 获取私有变量值
System.out.println("私有name:" + name);
System.out.println("最终对象:" + obj);
}
}
代码解释
- 公有变量直接操作
- 私有变量必须:
getDeclaredField+setAccessible(true) - 反射可以操作任何权限的变量,这是普通 Java 代码做不到的
3. 反射获取成员方法(0.9h)
核心 API
getMethod(String name, Class...):获取公有方法getDeclaredMethod(String name, Class...):获取任意方法(含私有)invoke(Object obj, args...):调用方法- 返回值:方法执行结果
完整代码示例
java
运行
import java.lang.reflect.Method;
public class ReflectMethod {
public static void main(String[] args) throws Exception {
Class<?> clazz = Class.forName("com.example.Student");
Object obj = clazz.newInstance();
// ====================== 1. 调用公有方法 study() ======================
Method studyMethod = clazz.getMethod("study");
studyMethod.invoke(obj); // 执行方法
// ====================== 2. 调用私有方法 sleep() ======================
Method sleepMethod = clazz.getDeclaredMethod("sleep");
sleepMethod.setAccessible(true); // 破封装
sleepMethod.invoke(obj); // 执行私有方法
// ====================== 3. 调用带参有返回值方法(补充) ======================
Method setNameMethod = clazz.getMethod("setName", String.class);
setNameMethod.invoke(obj, "王五");
Method getNameMethod = clazz.getMethod("getName");
String name = (String) getNameMethod.invoke(obj);
System.out.println("getName返回值:" + name);
}
}
核心重点
invoke()是反射调用方法的核心- 私有方法必须开启暴力访问
- 支持带参、带返回值的方法调用
三、晚上 1.5h:综合实操 + 复盘总结
必做练习(完整综合案例)
java
运行
// 反射综合实操:一行代码完成 创建对象 + 赋值 + 调用方法
public class ReflectTest {
public static void main(String[] args) throws Exception {
// 1. 获取Class
Class<?> clazz = Class.forName("com.example.Student");
// 2. 创建对象
Object obj = clazz.newInstance();
// 3. 赋值私有变量
java.lang.reflect.Field nameField = clazz.getDeclaredField("name");
nameField.setAccessible(true);
nameField.set(obj, "综合练习");
// 4. 赋值公有变量
java.lang.reflect.Field ageField = clazz.getField("age");
ageField.set(obj, 22);
// 5. 调用方法
java.lang.reflect.Method studyMethod = clazz.getMethod("study");
studyMethod.invoke(obj);
// 6. 输出结果
System.out.println(obj);
}
}
核心知识点总结
- 反射入口:
Class对象(三种获取方式) - 三大成员操作
- 构造:
Constructor→ 创建对象 - 变量:
Field→ 赋值 / 取值 - 方法:
Method→ 调用执行
- 构造:
- 暴力反射:
setAccessible(true)必须掌握 - 核心价值:动态、解耦、框架底层核心
重要补充:原计划遗漏的必备知识点
我帮你补充了面试高频、框架必用但计划里没写的关键内容:
1. 反射的优缺点
- 优点:动态、解耦、灵活性极高、框架必备
- 缺点:性能比普通代码低、破坏封装、安全性降低
2. Class.forName 会执行类的静态代码块
java
运行
Class.forName("com.example.Student"); // 会执行static代码块
- JDBC 连接数据库就是用这个特性
3. 反射获取父类、接口、注解
java
运行
// 获取父类
Class superClass = clazz.getSuperclass();
// 获取接口
Class[] interfaces = clazz.getInterfaces();
// 获取注解
Annotation[] annotations = clazz.getAnnotations();
4. 反射破坏单例模式
- 单例模式构造私有,但反射可以暴力调用私有构造,创建多个对象
- 这是高级面试高频考点
5. 数组、枚举、基本类型的 Class 对象
java
运行
Class<int[]> arrClass = int[].class;
Class<Season> enumClass = Season.class;
Class<Integer> intClass = int.class;
Day29 验收标准(完整版)
你完成今天学习后,必须达到:
- 能说出反射是什么、作用、场景
- 能默写三种获取 Class 对象的方式
- 会用反射:
- 创建对象
- 操作公有 / 私有变量
- 调用公有 / 私有方法
- 会写暴力反射代码
- 能独立完成反射操作实体类综合案例
- 知道反射是所有 Java 框架的底层原理
总结
这份内容完全覆盖你的学习计划,并做了深度拓展:
- 所有知识点都有详细解释
- 所有案例都有完整代码 + 逐行注释
- 补充了计划遗漏的高频重点(静态代码块、父类 / 注解、破坏单例、数组 Class 等)
- 层次清晰:上午入门→下午实操→晚上综合练习
- 完全贴合 Java 学习节奏,可直接跟着练习、面试、框架学习
更多推荐

所有评论(0)