
文章目录
- Java反射:从基础到框架应用的实战指南
-
- 一、反射介绍
-
- [1. 什么是反射?](#1. 什么是反射?)
- [2. 为什么需要反射?](#2. 为什么需要反射?)
- 二、反射的核心:Class类
-
- [1. 获取Class对象的三种方式](#1. 获取Class对象的三种方式)
-
- [方式1:通过 Class.forName(全类名)(运行时动态获取)](#方式1:通过 Class.forName(全类名)(运行时动态获取))
- [方式2:通过 类名.class(编译期已知类)](#方式2:通过 类名.class(编译期已知类))
- [方式3:通过 对象.getClass()(已有实例)](#方式3:通过 对象.getClass()(已有实例))
- 三、反射实战:操作类的结构
- 四、反射的应用场景
- 五、反射的优缺点
Java反射:从基础到框架应用的实战指南
一、反射介绍
1. 什么是反射?
简单来说,反射是Java提供的一种能力:允许程序在运行时获取类的详细信息(如属性、方法、构造器等),并动态操作这些信息。
正常情况下,我们使用类的流程是"编译期确定类 → 实例化 → 调用方法",比如:
java
User user = new User(); // 编译期已知User类
user.setName("张三");
而反射则是"运行时获取类信息 → 动态操作",即使编译期不知道具体类名,也能通过字符串(如配置文件中的类路径)完成对象创建和方法调用。

2. 为什么需要反射?
举个实际开发中的例子:假设你需要开发一个工具,根据用户配置的类名创建对象。如果没有反射,只能硬编码判断:
java
// 配置文件中读取的类名
String className = "com.example.Student";
// 不使用反射:必须提前知道所有可能的类,扩展性极差
if (className.equals("com.example.User")) {
return new User();
} else if (className.equals("com.example.Student")) {
return new Student();
} else {
// 新增类时必须修改代码
}
而有了反射,只需两行代码即可动态处理任意类:
java
Class<?> clazz = Class.forName(className); // 运行时加载类
Object obj = clazz.newInstance(); // 动态创建实例
这就是反射的核心价值:摆脱编译期的类型依赖,让程序更灵活、更具扩展性。
二、反射的核心:Class类
反射的所有操作都围绕java.lang.Class
类展开。每个类被JVM加载后,都会生成一个唯一的Class
对象,它包含了该类的所有信息(属性、方法、构造器等)。可以说,Class
对象是反射的"入口"。
1. 获取Class对象的三种方式
要使用反射,第一步是获取目标类的Class
对象,常用三种方式:
方式1:通过 Class.forName(全类名)(运行时动态获取)
最常用的方式,通过类的全限定名(包名+类名)动态加载,适合从配置文件或数据库中读取类名的场景:
java
// 需处理ClassNotFoundException(类不存在时抛出)
Class<?> clazz = Class.forName("com.example.User");
方式2:通过 类名.class(编译期已知类)
如果编译期就知道具体类,直接通过类名.class
获取,无需处理异常:
java
Class<User> userClass = User.class;
Class<String> stringClass = String.class;
方式3:通过 对象.getClass()(已有实例)
如果已有对象实例,调用其getClass()
方法:
java
User user = new User();
Class<?> clazz = user.getClass(); // 此时clazz即为User类的Class对象

注意:
Class.forName()
会触发类的初始化(执行静态代码块),而后两种方式仅加载类不初始化。
三、反射实战:操作类的结构
我们以一个Student
类为例,演示如何通过反射操作构造器、属性和方法:
java
import java.io.IOException;
public class Student {
private String name;
private int age;
public String gender;
public Student() {
}
public Student(String name) {
this.name = name;
}
protected Student(int age) {
this.age = age;
}
private Student(String name, int age) {
this.name = name;
this.age = age;
}
public Student(String name, int age, String gender) {
this.name = name;
this.age = age;
this.gender = gender;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
", gender='" + gender + '\'' +
'}';
}
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;
}
public void sleep(){
System.out.println("睡觉");
}
private void eat(String something) throws IllegalAccessError , IOException {
System.out.println("在吃"+something);
}
}
1. 利用反射获取构造方法(Constuctor)
通过反射调用构造器创建对象,支持无参和有参构造,包括私有构造器。
使用的方法

代码示例
java
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Parameter;
public class MyReflect_Constructor {
public static void main(String []args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
// 1.获取class字节码文件对象
Class clazz = Class. forName("Student");
// 2.获取所有公共构造方法
Constructor[] cons = clazz.getConstructors();
for(Constructor con : cons){
System.out.println(con);
}
System.out.println("==============");
// 获取所有构造方法,包括私有
Constructor[]cons2 = clazz.getDeclaredConstructors();
for(Constructor con : cons2){
System.out.println(con);
}
System.out.println("==============");
Constructor con3 = clazz.getConstructor();
System.out.println(con3);
Constructor con4 = clazz.getDeclaredConstructor(int.class);
System.out.println(con4);
Constructor con5 = clazz.getConstructor(String.class);
System.out.println(con5);
Constructor con6 = clazz.getDeclaredConstructor(String.class,int.class);
System.out.println(con6);
// 获取权限修饰符
int modifiers = con6.getModifiers();
System.out.println(modifiers);
// 获取对应构造方法的所有参数
Parameter[] parameters = con6.getParameters();
for(Parameter parameter :parameters){
System.out.println(parameter);
}
// 暴力反射:临时取消权限的校验 --> 利用私有构造方法创建对象
con6.setAccessible(true);
Student stu = (Student)con6.newInstance("林七夜",18);
System.out.println(stu);
}
}
运行结果:
public Student(java.lang.String)
public Student()
==============
private Student(java.lang.String,int)
protected Student(int)
public Student(java.lang.String)
public Student()
==============
public Student()
protected Student(int)
public Student(java.lang.String)
private Student(java.lang.String,int)
2
java.lang.String arg0
int arg1
Student@4554617c
方法区别:
getConstructor()
只能获取public构造器,getDeclaredConstructor()
可获取所有权限的构造器。
2. 利用反射获取成员变量(Field)
反射可以获取类的所有属性(包括私有),并读写其值。
使用的方法

代码示例
java
import java.lang.reflect.Field;
public class MyReflect_Field {
public static void main(String []args) throws ClassNotFoundException, NoSuchFieldException, IllegalAccessException {
// 1.获取class字节码文件的对象
Class clazz = Class.forName("Student");
// 2.获取成员变量
// 公共的
Field[] fields = clazz.getFields();
for (Field field : fields) {
System.out.println(field);
}
System.out.println("----------");
// 所有的
Field[] fields2 = clazz.getDeclaredFields();
for (Field field : fields2) {
System.out.println(field);
}
System.out.println("=========");
// 3.获取单个成员变量
// 私有
Field name = clazz.getDeclaredField("name");
System.out.println(name);
System.out.println("---------");
//公共
Field gender = clazz.getField("gender");
System.out.println(gender);
// 4.获取权限修饰符
int modifiers = name.getModifiers();
System.out.println(modifiers);
// 5.获取成员变量的名字
String n = name.getName();
System.out.println(n);
// 6.获取成员变量的数据类型
Class<?> type = name.getType();
System.out.println(type);
// 7.获取成员变量记录的值
Student s = new Student("张三",18,"男");
name.setAccessible(true);
String value = (String) name.get(s);
System.out.println(value);
// 8.修改对象里面的值
name.set(s,"李四");
System.out.println(s);
}
}
3. 调用方法(Method)
反射可以调用类的任意方法(包括私有方法),支持传递参数。
使用的方法

代码示例
java
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
public class MyReflect_Method {
public static void main(String []args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException {
// 1.获取class字节码文件对象
Class clazz = Class.forName("Student");
// 2.获取里面所有的方法对象(包含父类中的所有公共方法)
Method[] methods = clazz.getMethods();
for (Method method : methods) {
System.out.println(method);
}
System.out.println("-------------");
// 3. 获取子类的所有方法(不包括父类的,但包括本类的私有方法)
Method[] methods2 = clazz.getDeclaredMethods();
for (Method method : methods2) {
System.out.println(method);
}
// 4.获取单一指定方法
Method m = clazz.getDeclaredMethod("eat",String.class);
System.out.println(m);
// 5.获取方法的修饰符
int modifiers = m.getModifiers();
System.out.println(modifiers);
// 6.获取方法的名字
System.out.println(m.getName());
// 7.获取方法的形参
Parameter[] parameters = m.getParameters();
for (Parameter parameter : parameters) {
System.out.println(parameter);
}
// 8.获取方法抛出的异常
Class[] exceptionTypes = m.getExceptionTypes();
for (Class exceptionType : exceptionTypes) {
System.out.println(exceptionType);
}
// 9.Method类中用于创建对象的方法 (重点)
Student s = new Student();
m.setAccessible(true);
// 参数一s:表示方法的调用者
// 参数二"汉堡包":表示在调用方法是传递的实际参数
m.invoke(s,"汉堡包");
}
}
方法区别:
getMethod()
获取public方法,getDeclaredMethod()
获取所有权限的方法;invoke()
的第一个参数是实例(静态方法传null
),后续参数是方法的实际参数。
四、反射的应用场景
反射的灵活性使其成为框架设计的核心,但日常业务开发中需谨慎使用(避免过度设计)。常见应用场景包括:
- 框架的IOC容器:如Spring通过反射根据配置文件创建Bean,实现"控制反转";
- ORM框架:如MyBatis通过反射将数据库查询结果映射到Java对象的属性;
- 动态代理:AOP的实现依赖反射调用目标方法(如事务增强、日志记录);
- 注解解析 :自定义注解(如
@Controller
、@RequestMapping
)的生效需要反射扫描并处理; - 序列化/反序列化:JSON工具(如Jackson)通过反射将JSON字符串转换为Java对象。
五、反射的优缺点
优点:
- 动态性:运行时操作类,适应灵活配置场景(如通过配置文件切换实现类);
- 解耦:框架与业务类通过反射交互,无需硬编码依赖,降低耦合度;
- 通用性:一套反射代码可处理任意类,提升工具类的复用性。
缺点:
- 性能损耗:反射需要解析字节码,调用效率比直接调用低(但JVM已优化,非高频场景可忽略);
- 安全风险 :
setAccessible(true)
会绕过访问权限检查,可能破坏类的封装性; - 可读性差:反射代码较抽象,调试和维护成本高于直接调用。
如果我的内容对你有帮助,请 点赞 , 评论 , 收藏 。创作不易,大家的支持就是我坚持下去的动力!
