当前位置: 首页 > news >正文

Java:反射

一、反射的核心概念

1. 什么是反射?

反射的本质是在程序运行时,获取并操作类的所有信息的能力

  • 类的信息包括:成员变量、方法、构造函数、父类、接口、修饰符等。
  • 反射打破了编译期的访问限制,能直接操作private/protected修饰的成员。

2. 反射的前置:Java 类的生命周期

  1. 源代码阶段(.java 文件):程序员编写的源码文件,存储在磁盘上,人可直接阅读。
  2. 编译阶段(.class 文件):通过javac命令将.java 文件编译为二进制字节码文件,存储在磁盘上,程序无法直接操作。
  3. 类加载阶段(内存中的 Class 对象):通过java命令运行程序,JVM 将.class 文件加载到内存的方法区,生成唯一的Class对象(类对象),这是反射的操作入口。
  4. 运行时阶段(实例对象):程序运行时,通过new关键字创建类的实例对象,存储在堆内存中。

二、获取 Class 对象的三种方式

三种方式获取的是同一个 Class 对象(同一个类加载器下,一个类只会被加载一次)。

方式适用场景代码示例
类名.class编译期已知类名Class clazz = Animal.class;
对象.getClass()已有实例对象Animal animal = new Animal(); Class clazz = animal.getClass();
Class.forName("全类名")运行期动态获取(最常用)Class clazz = Class.forName("com.qcby.Animal");
// 三种方式获取Class对象,结果均为同一个对象 Class<?> clazz1 = Animal.class; Class<?> clazz2 = new Animal().getClass(); Class<?> clazz3 = Class.forName("com.qcby.animal.Animal"); System.out.println(clazz1 == clazz2); // true System.out.println(clazz1 == clazz3); // true

三、反射获取类的成员信息

1. 获取成员变量(Field)

核心方法
方法作用访问范围
getFields()获取所有public修饰的成员变量仅自身 + 父类的 public 成员
getDeclaredFields()获取本类中所有修饰符的成员变量仅本类的所有成员(含 private/protected/default)
getField("变量名")获取指定public成员变量仅 public
getDeclaredField("变量名")获取本类中指定成员变量无视修饰符
代码示例
Class<?> clazz = Animal.class; // 获取所有public成员变量 Field[] publicFields = clazz.getFields(); for (Field field : publicFields) { System.out.println("public成员:" + field.getName()); } // 获取本类所有成员变量(含private) Field[] allFields = clazz.getDeclaredFields(); for (Field field : allFields) { System.out.println("所有成员:" + field.getName()); } // 获取指定private成员变量 Field privateName = clazz.getDeclaredField("name"); // 暴力反射:解除访问权限限制 privateName.setAccessible(true);

2. 获取成员方法(Method)

核心方法
方法作用访问范围
getMethods()获取所有public修饰的方法自身 + 父类的 public 方法
getDeclaredMethods()获取本类所有修饰符的方法仅本类的所有方法
getMethod("方法名", 参数类型.class)获取指定public方法仅 public
getDeclaredMethod("方法名", 参数类型.class)获取本类指定方法无视修饰符
代码示例
Class<?> clazz = Animal.class; // 获取所有public方法(含父类) Method[] publicMethods = clazz.getMethods(); for (Method method : publicMethods) { System.out.println("public方法:" + method.getName()); } // 获取本类所有方法(含private) Method[] allMethods = clazz.getDeclaredMethods(); for (Method method : allMethods) { System.out.println("所有方法:" + method.getName()); } // 获取带参数的指定方法 Method flyMethod = clazz.getDeclaredMethod("fly", int.class, String.class); flyMethod.setAccessible(true);

3. 获取构造函数(Constructor)

核心方法
方法作用访问范围
getConstructors()获取所有public构造函数仅 public
getDeclaredConstructors()获取本类所有构造函数无视修饰符
getConstructor(参数类型.class)获取指定public构造函数仅 public
getDeclaredConstructor(参数类型.class)获取本类指定构造函数无视修饰符
代码示例
Class<?> clazz = Animal.class; // 获取无参构造函数 Constructor<?> noArgConstructor = clazz.getDeclaredConstructor(); noArgConstructor.setAccessible(true); Animal animal1 = (Animal) noArgConstructor.newInstance(); // 获取带参构造函数 Constructor<?> argConstructor = clazz.getDeclaredConstructor(String.class, int.class); argConstructor.setAccessible(true); Animal animal2 = (Animal) argConstructor.newInstance("小花", 18);

四、反射操作类的成员

1. 操作成员变量(赋值 / 取值)

Class<?> clazz = Animal.class; Animal animal = new Animal(); // 获取private成员变量并暴力反射 Field nameField = clazz.getDeclaredField("name"); nameField.setAccessible(true); // 取值:get(实例对象) String name = (String) nameField.get(animal); System.out.println("原始name:" + name); // 赋值:set(实例对象, 值) nameField.set(animal, "小黑"); System.out.println("修改后name:" + animal.getName());

2. 调用成员方法

Class<?> clazz = Animal.class; Animal animal = new Animal(); // 获取private方法并暴力反射 Method showMethod = clazz.getDeclaredMethod("show"); showMethod.setAccessible(true); // 调用方法:invoke(实例对象, 参数列表) showMethod.invoke(animal); // 调用带参数方法 Method flyMethod = clazz.getDeclaredMethod("fly", int.class, String.class); flyMethod.setAccessible(true); flyMethod.invoke(animal, 10, "黑色");

五、关键知识点总结

1.getDeclaredXXXgetXXX的区别

方法修饰符范围父类成员
getFields()/getMethods()/getConstructors()public包含
getDeclaredFields()/getDeclaredMethods()/getDeclaredConstructors()所有修饰符(含 private/protected/default)不包含

2. 暴力反射(setAccessible(true)

  • 作用:解除 Java 语言的访问权限检查,允许操作private/protected修饰的成员。
  • 必须场景:操作非public的成员变量、方法、构造函数时,必须调用此方法。
  • 注意:暴力反射会破坏封装性,仅在特殊场景(如框架开发)使用。

六、课后练习代码模板

Student类为例,完成以下任务:

  1. 定义Student类,包含private成员变量、方法、构造函数
  2. 通过反射获取并修改成员变量
  3. 通过反射调用普通方法和静态方法
  4. 反射创建实例对象
// 1. 定义Student类 class Student { private String name; public int age; private static String school = "河北大学"; public Student() {} private Student(String name) { this.name = name; } private void study() { System.out.println(name + "正在学习"); } public static void showSchool() { System.out.println("学校:" + school); } } // 2. 反射操作 public class ReflectDemo { public static void main(String[] args) throws Exception { Class<?> clazz = Class.forName("com.qcby.Student"); // 反射创建对象(私有构造) Constructor<?> constructor = clazz.getDeclaredConstructor(String.class); constructor.setAccessible(true); Student student = (Student) constructor.newInstance("小明"); // 修改成员变量 Field ageField = clazz.getField("age"); ageField.set(student, 18); Field nameField = clazz.getDeclaredField("name"); nameField.setAccessible(true); nameField.set(student, "小红"); // 调用方法 Method studyMethod = clazz.getDeclaredMethod("study"); studyMethod.setAccessible(true); studyMethod.invoke(student); // 调用静态方法 Method showSchoolMethod = clazz.getMethod("showSchool"); showSchoolMethod.invoke(null); // 静态方法传null } }

七、反射的优缺点

优点

  1. 动态性:程序运行时可操作类的信息,无需提前知道类的具体实现。
  2. 打破封装:能操作非public修饰的成员,适配框架开发场景。

缺点

  1. 性能损耗:反射绕过了编译期优化,运行效率较低。
  2. 破坏封装:暴力反射可能导致安全问题,降低代码可维护性。

八、例题

一、题目

定义实体类Student,并利用反射完成以下操作:

1.Student类定义要求

  • 私有属性
    • private String name
    • private final Integer stuId
    • private static String school
  • 构造方法
    • 私有无参构造
    • 私有有参构造
  • 方法
    • 普通公有方法
    • 私有自定义方法
    • 静态私有方法

2. 反射操作任务

  1. 获取Class对象,破解私有有无参构造创建实例
  2. 给普通私有属性赋值、读取(不依赖get/set,纯字段反射)
  3. 修改final修饰的私有常量属性(进阶考点)
  4. 修改 / 获取static静态私有属性
  5. 调用私有成员方法、静态私有方法

二、答案

1.Student实体类

public class Student { // 私有属性 private String name; private final Integer stuId; private static String school = "河北大学"; // 私有无参构造 private Student() { this.stuId = 0; } // 私有有参构造 private Student(String name, Integer stuId) { this.name = name; this.stuId = stuId; } // 普通公有方法 public void showInfo() { System.out.println("姓名:" + name + ", 学号:" + stuId + ", 学校:" + school); } // 私有自定义方法 private void study(String subject) { System.out.println(name + "正在学习:" + subject); } // 静态私有方法 private static void printSchool() { System.out.println("当前学校:" + school); } }

2. 反射操作测试类Test

import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.Method; public class Test { public static void main(String[] args) throws Exception { // 1. 获取 Class 对象 Class<?> clazz = Class.forName("Student"); // 2. 破解私有构造,创建实例 // 私有无参构造创建对象 Constructor<?> noArgConstructor = clazz.getDeclaredConstructor(); noArgConstructor.setAccessible(true); Student student1 = (Student) noArgConstructor.newInstance(); // 私有有参构造创建对象 Constructor<?> argConstructor = clazz.getDeclaredConstructor(String.class, Integer.class); argConstructor.setAccessible(true); Student student2 = (Student) argConstructor.newInstance("小明", 2023001); // 3. 普通私有属性 赋值、读取(不依赖 get/set) Field nameField = clazz.getDeclaredField("name"); nameField.setAccessible(true); // 赋值 nameField.set(student2, "小红"); // 读取 String nameValue = (String) nameField.get(student2); System.out.println("普通私有属性name的值:" + nameValue); // 4. 修改 final 修饰的私有常量属性(进阶考点) Field stuIdField = clazz.getDeclaredField("stuId"); stuIdField.setAccessible(true); stuIdField.set(student2, 2023002); System.out.println("final属性stuId的值:" + stuIdField.get(student2)); // 5. 修改 / 获取 static 静态私有属性 Field schoolField = clazz.getDeclaredField("school"); schoolField.setAccessible(true); // 获取静态属性值 String schoolValue = (String) schoolField.get(null); System.out.println("静态属性school的值:" + schoolValue); // 修改静态属性值 schoolField.set(null, "河北工业大学"); System.out.println("修改后静态属性school的值:" + schoolField.get(null)); // 6. 调用 私有成员方法、静态私有方法 // 私有成员方法 Method studyMethod = clazz.getDeclaredMethod("study", String.class); studyMethod.setAccessible(true); studyMethod.invoke(student2, "Java反射"); // 静态私有方法 Method printSchoolMethod = clazz.getDeclaredMethod("printSchool"); printSchoolMethod.setAccessible(true); printSchoolMethod.invoke(null); // 验证结果:调用公有方法查看最终数据 student2.showInfo(); } }

三、运行结果

普通私有属性name的值:小红 final属性stuId的值:2023002 静态属性school的值:河北大学 修改后静态属性school的值:河北工业大学 小红正在学习:Java反射 当前学校:河北工业大学 姓名:小红, 学号:2023002, 学校:河北工业大学

四、拆解说明

任务核心实现关键 API
破解私有构造创建实例调用getDeclaredConstructor获取私有构造,setAccessible(true)解除权限限制getDeclaredConstructor()newInstance()
普通私有属性读写直接通过Field对象的get/set操作,不依赖getter/settergetDeclaredField()get()set()
修改final属性反射绕过编译期final赋值限制,直接修改值setAccessible(true)set()
静态属性 / 方法操作静态成员属于类,操作时传入null代替实例对象get(null)set(null, value)invoke(null)
调用私有方法通过getDeclaredMethod获取私有方法,setAccessible(true)后调用invokegetDeclaredMethod()invoke()

补充说明

  • setAccessible(true)是反射操作非public成员的核心方法,用于解除 Java 的访问权限检查。
  • 修改final属性属于 “反常规操作”,仅作考点理解,实际开发中不推荐使用。
  • 静态成员(static)属于类本身,而非实例对象,因此操作时无需传入实例,直接传null即可。
http://www.jsqmd.com/news/706876/

相关文章:

  • hyperf 微服务架构方案大全
  • Linearis:现代高性能线性代数库的设计原理与异构计算实践
  • ImageNet挑战赛:计算机视觉深度学习的革命性转折
  • nli-MiniLM2-L6-H768作品分享:金融舆情报告中‘风险提示’与‘事件描述’中立性分析
  • AI代理技能库:模块化设计、核心技能与实战应用
  • 助贷CRM系统比较是什么?其主要特点应关注哪些方面?
  • 用 Python 批量制造表情包,从此聊天斗图没输过
  • AI模型部署效率提升210%,Docker AI Toolkit 2026到底重构了哪4层编排协议?
  • 阿里云国际站服务器DNS服务器设置成什么?服务器dns怎么填写?
  • 基于Qwen3.5-2B的智能日志聚合分析:从海量运维日志中快速定位问题
  • EasyAnimateV5图生视频部署:Nginx反向代理配置支持HTTPS与域名访问
  • Nixtla时间序列预测生态:统一接口、高速统计与深度学习模型实战
  • Phi-3.5-Mini-Instruct部署案例:高校AI教学实验平台轻量化部署方案
  • 成都地区、H型钢、400X200X8X13、Q235B、安泰、现货批发供应 - 四川盛世钢联营销中心
  • sklearn多核机器学习性能优化实战指南
  • C/C++:类型转换
  • 3步掌握ChanlunX缠论插件:通达信技术分析终极指南
  • 京东大屏AI手机+东东APP:银发智能,诚意够!
  • 成都地区、H型钢、350X350X12X19、Q235B、安泰、现货批发供应 - 四川盛世钢联营销中心
  • Ubuntu——常见基本命令
  • 2026绵阳玄关柜定制优质公司TOP5推荐:绵阳轻奢全屋定制/绵阳酒柜定制/绵阳阳台柜定制/绵阳高端家居定制/绵阳书房定制/选择指南 - 优质品牌商家
  • 教程太碎总失败?这篇Claude Code配置文:从Node.js到API调用一篇搞定(亲测跑通)(Windows系统)
  • 神经形态视觉传感器与3D堆叠计算架构解析
  • Vulkan GPU图像处理之幂律(伽马)变换:Kompute框架实战与性能分析
  • scikit-learn预测建模全流程解析与实战技巧
  • Docker技术入门与实战【2.6】
  • 机器学习中三大均值方法的应用与优化策略
  • Keras构建词汇级神经语言模型实战指南
  • 2026年Q2成都旧电脑专业回收标杆名录:成都回收/成都废旧金属回收/成都旧电脑回收/成都火锅店设备回收/成都酒店设备回收/选择指南 - 优质品牌商家
  • Real-ESRGAN-ncnn-vulkan:3分钟让模糊图像焕然新生的AI超分辨率神器