news 2026/4/27 5:02:46

Java:反射

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
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即可。
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/27 4:58:28

VCG 网格整形(Smoothed ARAP)

文章目录 一、简介 二、实现代码 三、实现效果 参考资料 一、简介 虽然 ARAP算法在许多情况下都能够产生良好的结果,但它也有一些局限性,例如在处理大幅度形状变化或复杂边界条件下可能效果不佳。因此就有一些学者尝试添加平滑项,抑制变形过程中出现的不自然形状,公式如下所…

作者头像 李华
网站建设 2026/4/27 4:53:49

EasyAnimateV5图生视频部署:Nginx反向代理配置支持HTTPS与域名访问

EasyAnimateV5图生视频部署&#xff1a;Nginx反向代理配置支持HTTPS与域名访问 你是不是已经成功部署了EasyAnimateV5图生视频模型&#xff0c;但还在用IP地址加端口号的方式访问服务&#xff1f;每次都要输入一长串的http://183.93.148.87:7860&#xff0c;不仅难记&#xff…

作者头像 李华
网站建设 2026/4/27 4:52:23

AWS EC2上部署XGBoost实现高效机器学习训练

1. 项目概述在机器学习领域&#xff0c;XGBoost因其卓越的性能和效率而广受欢迎。然而&#xff0c;当处理大规模数据集时&#xff0c;本地计算机的计算资源往往捉襟见肘。这时&#xff0c;云计算平台如Amazon Web Services&#xff08;AWS&#xff09;就成为了理想的选择。本文…

作者头像 李华
网站建设 2026/4/27 4:48:26

【技术突破】ROFLPlayer:重塑英雄联盟回放分析的智能引擎

【技术突破】ROFLPlayer&#xff1a;重塑英雄联盟回放分析的智能引擎 【免费下载链接】ROFL-Player (No longer supported) One stop shop utility for viewing League of Legends replays! 项目地址: https://gitcode.com/gh_mirrors/ro/ROFL-Player ROFLPlayer是一款专…

作者头像 李华