
前言:什么是反射?为什么需要它?
你是否好奇过:Spring 框架如何根据配置文件自动创建对象?ORM 框架如何直接操作类的私有属性?这些 "黑科技" 的底层核心,正是 Java 的反射机制。
简单来说,反射就是程序在运行时可以 "看透" 类的内部结构(包括属性、方法、构造器等),并动态操作这些结构的能力。就像给程序装上了 "透视眼",即使编译时不知道类的具体信息,运行时也能灵活操控。
一、反射的基石:Class 对象
要使用反射,必须先获取目标类的Class
对象 ------ 它是反射的 "入口",包含了类的所有元信息(属性、方法、构造器等)。
获取 Class 对象的 3 种方式
- 对象.getClass ():通过实例获取(已创建对象时使用)
- 类名.class:通过类名直接获取(编译时已知类)
- Class.forName ("全类名"):通过类的全路径获取(最常用,动态加载类
这三种方式获取的是同一个Class
对象(每个类在 JVM 中只有一个 Class 实例)。
直观理解 Class 对象的作用
下面的图展示了 Class 对象作为 "类元信息载体" 的核心作用:

从图中可以清晰看到:Class 对象就像类的 "说明书",反射通过这份说明书,就能操作原本不可见的类成员。
二、反射应用一:动态创建对象
反射创建对象有两种方式:通过无参构造器和通过有参构造器。
1. 通过无参构造器创建对象
步骤:
- 获取 Class 对象
- 调用
newInstance()
方法(JDK9 + 推荐用getDeclaredConstructor().newInstance()
)
2. 通过有参构造器创建对象
步骤:
- 获取 Class 对象
- 通过
getDeclaredConstructor(参数类型...)
获取指定构造器 - 调用构造器的
newInstance(参数值...)
创建对象
java
public class ReflectionDemo {
public static void main(String[] args) throws Exception {
Class<?> userClass = Class.forName("com.example.reflection.User");
// 获取有参构造器(参数为String和int)
Constructor<?> constructor = userClass.getDeclaredConstructor(String.class, int.class);
// 创建对象(传入参数)
User user = (User) constructor.newInstance("张三", 20);
System.out.println(user); // 输出:User{name='张三', age=20}
}
}
对象创建流程可视化

三、反射应用二:调用方法(含私有方法)
反射可以调用类的任意方法,包括私有方法。核心是通过Method
类操作。
1. 调用公有方法
步骤:
- 获取 Class 对象和实例
- 通过
getMethod(方法名, 参数类型...)
获取公有方法 - 调用
method.invoke(实例, 参数值...)
执行方法
java
class User {
// 公有方法
public void publicMethod(String msg) {
System.out.println("公有方法:" + msg);
}
// 私有方法
private void privateMethod(int num) {
System.out.println("私有方法:数字=" + num);
}
}
public class ReflectionDemo {
public static void main(String[] args) throws Exception {
Class<?> userClass = User.class;
User user = (User) userClass.newInstance();
// 调用公有方法
Method publicMethod = userClass.getMethod("publicMethod", String.class);
publicMethod.invoke(user, "Hello 反射"); // 输出:公有方法:Hello 反射
}
}
2. 调用私有方法
私有方法需要额外一步:通过setAccessible(true)
绕过访问权限检查(核心操作!)
java
public class ReflectionDemo {
public static void main(String[] args) throws Exception {
Class<?> userClass = User.class;
User user = (User) userClass.newInstance();
// 调用私有方法
Method privateMethod = userClass.getDeclaredMethod("privateMethod", int.class);
// 关键:设置可访问(绕过权限检查)
privateMethod.setAccessible(true);
privateMethod.invoke(user, 666); // 输出:私有方法:数字=666
}
}
私有方法调用的核心逻辑
为什么setAccessible(true)
能访问私有方法?看下图的解析:

简单说:setAccessible(true)
会关闭 Java 的访问权限检查,让反射可以直接操作私有成员(但会破坏封装性,需谨慎使用)。
四、反射应用三:修改属性(含私有属性)
修改属性的逻辑和调用方法类似,核心是Field
类,私有属性同样需要setAccessible(true)
。
1. 修改公有属性
java
class User {
public String publicField; // 公有属性
private int privateField; // 私有属性
}
public class ReflectionDemo {
public static void main(String[] args) throws Exception {
Class<?> userClass = User.class;
User user = (User) userClass.newInstance();
// 修改公有属性
Field publicField = userClass.getField("publicField");
publicField.set(user, "公有属性值");
System.out.println(user.publicField); // 输出:公有属性值
}
}
2. 修改私有属性
java
public class ReflectionDemo {
public static void main(String[] args) throws Exception {
Class<?> userClass = User.class;
User user = (User) userClass.newInstance();
// 修改私有属性
Field privateField = userClass.getDeclaredField("privateField");
privateField.setAccessible(true); // 关键:允许访问私有属性
privateField.set(user, 100); // 设置值
// 读取私有属性值
int value = (int) privateField.get(user);
System.out.println(value); // 输出:100
}
}
私有属性修改流程

五、反射的利弊与注意事项
优点
- 灵活性高:动态操作类,适合框架开发(如 Spring、MyBatis)
- 解耦:不依赖编译时类信息,降低代码耦合度
- 扩展性强:可通过配置文件动态加载类,无需修改代码
缺点
- 性能开销:反射操作绕开了编译期检查,性能比直接调用低(约慢 10-100 倍)
- 破坏封装:直接操作私有成员,违反面向对象设计原则
- 安全性风险:可能被恶意利用(如绕过权限检查攻击)
- 代码可读性差:反射代码较繁琐,不如直接调用直观
注意事项
- 非必要不使用反射(优先直接调用)
- 反射操作需处理大量异常(
NoSuchMethodException
、IllegalAccessException
等) - 对性能敏感的场景(如高频调用)避免使用反射
- 私有成员操作需谨慎,确保符合业务逻辑
总结:反射的价值与应用场景
反射是 Java 中 "动态性" 的核心体现,虽然有性能和封装性的代价,但在框架开发、动态代理、序列化等场景中不可替代:
- 框架开发:Spring IOC 容器通过反射创建 Bean,MyBatis 通过反射映射数据库字段
- 动态代理:AOP 的实现基础(如 Spring AOP)
- 序列化 / 反序列化:JSON 框架(如 Jackson)通过反射读写对象属性
- 注解处理 :通过反射解析类 / 方法上的注解(如 JUnit 的
@Test
)
掌握反射,能让你看透 Java 框架的底层逻辑,写出更灵活、更具扩展性的代码。但记住:反射是把 "双刃剑",合理使用才能发挥其最大价值。
最后 :反射的核心是 "运行时获取类信息并操作",关键 API 是Class
、Constructor
、Method
、Field
,而setAccessible(true)
是操作私有成员的 "钥匙"。多动手实践,才能真正理解反射的精髓!
原创声明:本文为CSDN博主梵得儿SHI原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
觉得文章对你有帮助?点个赞👍支持一下!有疑问欢迎在评论区讨论~
