反射

Java的反射(Reflection)是一种允许程序在运行时动态访问、检测和修改自身结构和行为的机制。
通过反射,Java代码可以获取类的信息(如类名、方法、字段、构造器等),
甚至操作类的私有成员、动态创建对象、调用方法等。以下是反射的核心概念和用法:
​为什么叫“反射”?
“反射”这一名称来源于“程序能够像镜子一样观察自身结构”的比喻:

​反射(Reflection)​​ 的字面意义是“映射、倒影”。
在编程中,它表示程序在运行时可以“反向映射”自身的结构,
例如类的定义、方法、属性等元数据。
反射机制让程序不再局限于“静态”的代码结构,
而是可以在运行时动态“反映”出类的内部细节,从而实现灵活的编程。

核心作用

反射的核心作用:

  • 动态获取类的信息:在运行时分析类的结构。
  • 动态创建对象:通过类名实例化对象。
  • 动态调用方法:根据方法名和参数调用方法。
  • 访问私有成员:突破访问权限限制(需主动授权)。
  • 通用框架开发:如SpringHibernate等框架依赖反射实现依赖注入、动态代理等。

反射的核心类

  • Class类:表示一个类或接口,是所有反射操作的入口。

获取类的class对象:

通过类名.class:
Class<User> clazz = User.class;
通过对象实例的getClass()方法:
User user = new User();
Class<?> clazz = user.getClass();
通过Class.forName(“全限定类名”):
Class<?> clazz = Class.forName("com.example.User"); // 需处理ClassNotFoundException

创建对象实例:

// 通过无参构造器创建对象
User user = clazz.newInstance(); // 已过时,推荐用getDeclaredConstructor().newInstance()
// 通过有参构造器创建对象
Constructor<?> constructor = clazz.getConstructor(String.class, int.class);
User user = (User) constructor.newInstance("Alice", 25);

调用方法:

Method method = clazz.getMethod("setName", String.class); // 获取公有方法
method.invoke(user, "Bob"); // 调用方法

// 调用私有方法
Method privateMethod = clazz.getDeclaredMethod("privateMethod");
privateMethod.setAccessible(true); // 突破访问限制
privateMethod.invoke(user);

访问字段(属性):

Field field = clazz.getDeclaredField("name");
field.setAccessible(true); // 访问私有字段
field.set(user, "Charlie"); // 设置值
String name = (String) field.get(user); // 获取值
  • Constructor类:表示类的构造方法,用于创建对象。

和类名一样的函数:

public class MyClass {
public MyClass(String name) {
System.out.println("公共构造方法调用,name: " + name);
}
}

// 反射调用
Constructor<MyClass> constructor = MyClass.class.getConstructor(String.class);
MyClass obj = constructor.newInstance("Alice");

常用命令执行类:ProcessBuilder

Class clazz = Class.forName("java.lang.ProcessBuilder");
((ProcessBuilder)
clazz.getConstructor(List.class).newInstance(Arrays.asList("calc.exe"))).star
t();

Class clazz = Class.forName("java.lang.ProcessBuilder");
clazz.getMethod("start").invoke(clazz.getConstructor(List.class).newInstance(
Arrays.asList("calc.exe")));
  • Method类:表示类的方法,用于调用方法。

核心是invoke(调用)方法
获取 Method 对象:

获取公共方法(包括继承的)。
Class.getMethod(String name, Class<?>... parameterTypes)

Class clazz = Class.forName("java.lang.Runtime");
clazz.getMethod("exec",
String.class).invoke(clazz.getMethod("getRuntime").invoke(clazz),
"calc.exe");


获取本类中声明的方法(包括私有方法)。
Class.getDeclaredMethod(String name, Class<?>... parameterTypes)

Class clazz = Class.forName("java.lang.Runtime");
Constructor m = clazz.getDeclaredConstructor();
m.setAccessible(true);
clazz.getMethod("exec", String.class).invoke(m.newInstance(), "calc.exe");

setAccessible ,这个是必须的。

示例:

import java.lang.reflect.Method;

public class Demo {
public static void main(String[] args) throws Exception {
// 获取 String 类的 toUpperCase 方法
Method method = String.class.getMethod("toUpperCase");

// 创建对象实例
String str = "hello";

// 调用方法:str.toUpperCase()
Object result = method.invoke(str); // 参数为对象实例(str)和空参数

System.out.println(result); // 输出:HELLO
}
}

示例2:带参数

import java.lang.reflect.Method;

public class MathUtils {
public static int add(int a, int b) {
return a + b;
}
}

public class Demo {
public static void main(String[] args) throws Exception {
// 获取静态方法 add(int, int)
Method method = MathUtils.class.getMethod("add", int.class, int.class);

// 调用静态方法(obj 参数传 null)
Object result = method.invoke(null, 3, 5);

System.out.println(result); // 输出:8
}
}
  • Field类:表示类的字段(成员变量),用于读写字段值。

final Field field = getField(obj.getClass(), fieldName);
field.set(obj, value);
  • Modifier类:解析类、方法或字段的修饰符(如publicprivate)。

恶意类示例

import java.lang.Runtime;
import java.lang.Process;
public class TouchFile {
static {
try {
Runtime rt = Runtime.getRuntime();
String[] commands = {"touch", "/tmp/success"};
Process pc = rt.exec(commands);
pc.waitFor();
} catch (Exception e) {
// do nothing
}
}
}