1. 框架开发 (Framework Development)
-
场景: 框架需要在运行时动态地加载类、创建对象、调用方法,而不需要在编译时知道这些信息。
-
例子:Spring Framework 的依赖注入 (Dependency Injection)
Spring 框架使用反射来实现依赖注入,在运行时动态地将依赖对象注入到目标对象中。
// 示例代码(简化版,仅用于说明原理) // 自定义注解 @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.FIELD) public @interface Autowired {} // 待注入的类 public class MyService { @Autowired private MyRepository repository; // 需要注入的依赖 public void doSomething() { repository.saveData("Hello, Reflection!"); } } // 依赖类 public class MyRepository { public void saveData(String data) { System.out.println("Saving data: " + data); } } // 实现依赖注入的类 public class DIContainer { public static void inject(Object obj) throws Exception { Class<?> clazz = obj.getClass(); for (Field field : clazz.getDeclaredFields()) { if (field.isAnnotationPresent(Autowired.class)) { field.setAccessible(true); // 允许访问私有字段 Class<?> fieldType = field.getType(); Object dependency = fieldType.newInstance(); // 创建依赖对象 field.set(obj, dependency); // 注入依赖对象 } } } public static void main(String[] args) throws Exception { MyService service = new MyService(); DIContainer.inject(service); // 注入依赖 service.doSomething(); // 调用 service 方法 } }- 解释:
@Autowired注解用于标记需要注入的字段。DIContainer.inject()方法使用反射来遍历类的所有字段,找到带有@Autowired注解的字段,然后创建依赖对象,并将依赖对象注入到目标对象中。- 通过这种方式,
MyService类不需要手动创建MyRepository对象,而是由DIContainer动态地注入。
- 好处:
- 降低了组件之间的耦合度,提高了代码的可维护性和可测试性。
- 可以在运行时动态地配置组件之间的依赖关系。
- 解释:
-
例子:MyBatis 的 SQL 映射
MyBatis 使用反射来将数据库查询结果映射到 Java 对象。
// 示例代码(简化版,仅用于说明原理) // 数据库查询结果 Map<String, Object> row = new HashMap<>(); row.put("id", 1); row.put("name", "John Doe"); row.put("email", "john.doe@example.com"); // Java 对象 public class User { private int id; private String name; private String email; // Getter 和 Setter 方法 (省略) } // 使用反射将数据库查询结果映射到 Java 对象 public class ObjectMapper { public static <T> T mapRowToObject(Map<String, Object> row, Class<T> clazz) throws Exception { T obj = clazz.newInstance(); // 创建对象 for (Map.Entry<String, Object> entry : row.entrySet()) { String columnName = entry.getKey(); Object columnValue = entry.getValue(); String methodName = "set" + Character.toUpperCase(columnName.charAt(0)) + columnName.substring(1); // 构造 Setter 方法名 try { Method method = clazz.getMethod(methodName, columnValue.getClass()); // 获取 Setter 方法 method.invoke(obj, columnValue); // 调用 Setter 方法 } catch (NoSuchMethodException e) { // 如果没有对应的 Setter 方法,则忽略 } } return obj; } }- 解释:
ObjectMapper.mapRowToObject()方法使用反射来遍历数据库查询结果的每一列,并根据列名构造 Setter 方法名。- 然后,使用
clazz.getMethod()方法获取对应的 Setter 方法,并使用method.invoke()方法调用 Setter 方法,将数据库查询结果的值设置到 Java 对象中。
- 好处:
- 实现了数据库表与 Java 对象的映射,简化了数据访问代码的编写。
- 可以在运行时动态地映射不同的数据库表和 Java 对象。
- 解释:
2. 序列化和反序列化 (Serialization and Deserialization)
-
场景: 需要将 Java 对象转换为字节流,以便进行网络传输或持久化存储。 在反序列化时,需要将字节流转换为 Java 对象。
-
例子:自定义序列化/反序列化框架
// 示例代码(简化版,仅用于说明原理) // 使用反射实现序列化 public class Serializer { public static String serialize(Object obj) throws Exception { Class<?> clazz = obj.getClass(); StringBuilder sb = new StringBuilder(); sb.append("{" + clazz.getName() + ":"); for (Field field : clazz.getDeclaredFields()) { field.setAccessible(true); String fieldName = field.getName(); Object fieldValue = field.get(obj); sb.append(fieldName + "=" + fieldValue + ","); } sb.append("}"); return sb.toString(); } } // 使用反射实现反序列化 public class Deserializer { public static Object deserialize(String str) throws Exception { // (简化处理,假设字符串格式固定) String className = str.substring(1, str.indexOf(":")); // 提取类名 Class<?> clazz = Class.forName(className); Object obj = clazz.newInstance(); // 创建对象 // ... (解析字符串,设置字段值) ... // 这里需要更复杂的字符串解析逻辑,并使用反射设置字段值 return obj; } }- 解释:
Serializer.serialize()方法使用反射来遍历对象的所有字段,获取字段名和字段值,并将它们拼接成一个字符串。Deserializer.deserialize()方法使用反射来根据类名创建对象,并解析字符串,将字段值设置到对象中。
- 好处:
- 可以灵活地控制序列化和反序列化的过程。
- 可以处理复杂的对象关系。
- 解释:
3. 单元测试 (Unit Testing)
-
场景: 需要测试类的私有方法或私有字段,但无法直接访问这些成员。
-
例子:使用反射来访问私有成员
import org.junit.jupiter.api.Test; import java.lang.reflect.Field; import java.lang.reflect.Method; import static org.junit.jupiter.api.Assertions.*; class MyClassTest { @Test void testPrivateField() throws Exception { MyClass obj = new MyClass(); Field privateField = MyClass.class.getDeclaredField("privateField"); privateField.setAccessible(true); // 允许访问私有字段 privateField.set(obj, 100); // 设置私有字段的值 assertEquals(100, obj.getPrivateFieldValue()); // 假设 MyClass 有一个 getPrivateFieldValue() 方法用于测试 } @Test void testPrivateMethod() throws Exception { MyClass obj = new MyClass(); Method privateMethod = MyClass.class.getDeclaredMethod("privateMethod"); privateMethod.setAccessible(true); // 允许访问私有方法 String result = (String) privateMethod.invoke(obj); // 调用私有方法 assertEquals("Hello from private method", result); } } class MyClass { private int privateField; private String privateMethod() { return "Hello from private method"; } public int getPrivateFieldValue() { return privateField; } }- 解释:
MyClassTest类使用 JUnit 框架进行单元测试。testPrivateField()方法使用反射来访问MyClass的私有字段privateField,并设置其值。testPrivateMethod()方法使用反射来调用MyClass的私有方法privateMethod()。
- 好处:
- 可以测试类的内部实现细节,提高测试覆盖率。
- 可以在不修改原始类代码的情况下进行测试。
- 解释:
4. 动态代理 (Dynamic Proxy)
- 场景: 需要在运行时动态地创建代理对象,对方法进行增强或拦截。
- 例子:AOP (面向切面编程)
AOP 是一种编程范式,用于将横切关注点(例如日志记录、安全检查、事务管理)从核心业务逻辑中分离出来。 Java 动态代理可以用来实现 AOP。
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
// 接口
interface MyInterface {
void doSomething();
}
// 实现类
class MyClass implements MyInterface {
@Override
public void doSomething() {
System.out.println("MyClass is doing something...");
}
}
// 动态代理
class MyInvocationHandler implements InvocationHandler {
private Object target; // 被代理的对象
public MyInvocationHandler(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("Before method: " + method.getName()); // 前置增强
Object result = method.invoke(target, args); // 调用原始方法
System.out.println("After method: " + method.getName()); // 后置增强
return result;
}
}
// 示例代码
public class DynamicProxyExample {
public static void main(String[] args) {
MyInterface target = new MyClass(); // 创建目标对象
MyInvocationHandler handler = new MyInvocationHandler(target); // 创建调用处理器
// 创建代理对象
MyInterface proxy = (MyInterface) Proxy.newProxyInstance(
MyInterface.class.getClassLoader(),
new Class[] {MyInterface.class},
handler
);
proxy.doSomething(); // 调用代理对象的方法,会被拦截
}
}
- 解释:
MyInvocationHandler类实现了InvocationHandler接口,用于拦截方法的调用。Proxy.newProxyInstance()方法使用反射来创建代理对象。- 当调用代理对象的方法时,实际上会调用
MyInvocationHandler.invoke()方法,可以在该方法中进行增强或拦截。
- 好处:
- 实现了横切关注点与核心业务逻辑的分离,提高了代码的可维护性和可重用性.
- 可以在运行时动态地添加或删除切面。
334



被折叠的 条评论
为什么被折叠?



