反射
概念
个人理解反射就是Java能在仅知道类的路径(java.lang.Runtime
)和类名的情况下动态的调用里面的方法
代码示例
假设目标存在一个User方法,代码如下:
public class User {
private String name;
private int age;
public User() {
System.out.println("调用无参构造函数");
}
public User(String name, int age) {
this.name = name;
this.age = age;
System.out.println("调用有参构造函数");
}
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 "User{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
使用反射代码示例:
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
public class ReflectionExample {
public static void main(String[] args) throws Exception {
// 获取 Class 对象的几种方式
// 方式1: 通过类名.class
Class<User> userClass1 = User.class;
// 方式2: 通过实例对象的 getClass() 方法
User user = new User();
Class userClass2 = user.getClass();
// 方式3: 通过 Class.forName() 方法(最常用,可以动态加载类)
Class<?> userClass3 = Class.forName("User"); // 包名+类名
System.out.println("--- 1. 创建对象:通过反射调用构造函数 ---");
// 获取无参构造函数并创建对象
Constructor<User> constructor = userClass1.getDeclaredConstructor();
User user1 = constructor.newInstance(); // 相当于 new User()
System.out.println("创建的对象1: " + user1);
// 获取有参构造函数并创建对象
Constructor<User> constructorWithParams = userClass1.getDeclaredConstructor(String.class, int.class);
User user2 = constructorWithParams.newInstance("张三", 25); // 相当于 new User("张三", 25)
System.out.println("创建的对象2: " + user2);
System.out.println("\n--- 2. 调用方法:通过反射调用方法 ---");
// 获取 setName 方法
Method setNameMethod = userClass1.getDeclaredMethod("setName", String.class);
// 调用 setName 方法,参数为 (对象实例, 方法参数)
setNameMethod.invoke(user1, "李四");
System.out.println("调用setName方法后的对象: " + user1);
// 获取 getName 方法
Method getNameMethod = userClass1.getDeclaredMethod("getName");
// 调用 getName 方法
String name = (String) getNameMethod.invoke(user1);
System.out.println("调用getName方法获取到的值: " + name);
System.out.println("\n--- 3. 访问成员变量:通过反射获取和修改私有成员变量 ---");
// 获取 name 成员变量,包括私有变量
Field nameField = userClass1.getDeclaredField("name");
// 如果成员变量是私有的,需要设置为可访问
nameField.setAccessible(true);
// 获取 name 的值
String fieldName = (String) nameField.get(user2);
System.out.println("获取到的name字段值: " + fieldName);
// 修改 name 的值
nameField.set(user2, "王五");
System.out.println("修改name字段后的对象: " + user2);
}
}
假设只知道User类名,其他的啥都不知道,要先调出存在的方法再去执行其中一个,代码如下:
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.util.Arrays;
public class DynamicMethodCaller {
public static void main(String[] args) throws Exception {
// 假设我们只知道类名是 "User"
String className = "User";
// 假设我们要调用的方法是 "setName"
String targetMethodName = "setName";
// 假设要传入的参数值是 "张三"
Object[] arguments = {"张三"};
// 1. 获取 Class 对象
Class<?> clazz = Class.forName(className);
// 2. 动态获取并分析方法
Method targetMethod = null;
System.out.println("正在寻找方法: " + targetMethodName);
// 获取所有公共方法
Method[] methods = clazz.getMethods();
for (Method method : methods) {
// 找到名字匹配的方法
if (method.getName().equals(targetMethodName)) {
targetMethod = method;
System.out.println(" - 找到目标方法: " + method.getName());
// 获取参数数量
int paramCount = method.getParameterCount();
System.out.println(" - 参数数量: " + paramCount);
// 获取并打印参数类型
if (paramCount > 0) {
Class<?>[] paramTypes = method.getParameterTypes();
System.out.println(" - 参数类型: " + Arrays.toString(paramTypes));
}
break; // 找到后立即退出循环
}
}
// 3. 动态调用方法
if (targetMethod != null) {
// 获取无参构造函数来创建实例
Object instance = clazz.getDeclaredConstructor().newInstance();
// 检查传入的参数数量是否与方法需要的参数数量匹配
if (targetMethod.getParameterCount() != arguments.length) {
System.err.println("错误: 传入的参数数量不匹配!");
return;
}
System.out.println("\n正在调用方法...");
// 调用 invoke 方法,传入实例和参数
targetMethod.invoke(instance, arguments);
// 验证结果
Method getNameMethod = clazz.getMethod("getName");
Object result = getNameMethod.invoke(instance);
System.out.println("调用成功!结果为: " + result);
} else {
System.err.println("错误: 找不到方法 " + targetMethodName + "!");
}
}
}
反射调用执行命令
Runtime.getRuntime().exec(String command)
import java.lang.reflect.Method;
public class SimplifiedReflectiveCalcExec1 {
public static void main(String[] args) throws Exception {
// 获取 Runtime 类的 Class 对象
Class<?> runtimeClass = Class.forName("java.lang.Runtime");
// 获取 getRuntime() 静态方法并调用,获取 Runtime 实例
Method getRuntimeMethod = runtimeClass.getMethod("getRuntime");
Object runtimeInstance = getRuntimeMethod.invoke(null);
// 获取 exec(String) 方法并调用,执行命令
Method execMethod = runtimeClass.getMethod("exec", String.class);
execMethod.invoke(runtimeInstance, "calc.exe");
}
}
思维导图:
反射调用 ProcessBuilder
(间接方式)
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
public class SimplifiedReflectiveProcessBuilderCalc {
public static void main(String[] args) throws Exception {
// 获取 ProcessBuilder 类的 Class 对象
Class<?> processBuilderClass = Class.forName("java.lang.ProcessBuilder");
// 获取 ProcessBuilder 的 String... command 构造函数
Constructor<?> constructor = processBuilderClass.getConstructor(String[].class);
// 准备命令参数
String[] command = {"calc.exe"};
// 通过反射实例化 ProcessBuilder
Object processBuilderInstance = constructor.newInstance(new Object[]{command});
// 获取 start() 方法并调用,执行命令
Method startMethod = processBuilderClass.getMethod("start");
startMethod.invoke(processBuilderInstance);
}
}