Java反射机制详解:动态类加载与方法调用
Java反射机制详解:动态类加载与方法调用
概述
反射是Java中强大的特性,它允许程序在运行时获取类的信息,并动态地创建对象、调用方法、访问字段。反射是框架设计的基础,如Spring、Hibernate等。
1. 获取Class对象
public class GetClassExample {
public static void main(String[] args) throws Exception {
// 方式1:通过类名.class
Class<?> clazz1 = String.class;
System.out.println("方式1: " + clazz1.getName());
// 方式2:通过对象.getClass()
String str = "Hello";
Class<?> clazz2 = str.getClass();
System.out.println("方式2: " + clazz2.getName());
// 方式3:通过Class.forName()
Class<?> clazz3 = Class.forName("java.lang.String");
System.out.println("方式3: " + clazz3.getName());
// 获取类信息
System.out.println("类名: " + clazz3.getSimpleName());
System.out.println("包名: " + clazz3.getPackage().getName());
System.out.println("父类: " + clazz3.getSuperclass().getName());
System.out.println("接口: " + java.util.Arrays.toString(clazz3.getInterfaces()));
System.out.println("是否是数组: " + clazz3.isArray());
System.out.println("是否是接口: " + clazz3.isInterface());
}
}
2. 创建对象
import java.lang.reflect.*;
public class CreateObjectExample {
public static void main(String[] args) throws Exception {
Class<?> clazz = Class.forName("java.lang.StringBuilder");
// 使用无参构造方法
Object obj1 = clazz.getDeclaredConstructor().newInstance();
System.out.println("无参构造: " + obj1);
// 使用有参构造方法
Constructor<?> constructor = clazz.getDeclaredConstructor(String.class);
Object obj2 = constructor.newInstance("Hello");
System.out.println("有参构造: " + obj2);
// 访问私有构造方法
Class<?> privateClass = Class.forName("PrivateClass");
Constructor<?> privateConstructor = privateClass.getDeclaredConstructor();
privateConstructor.setAccessible(true); // 允许访问私有成员
Object obj3 = privateConstructor.newInstance();
System.out.println("私有构造: " + obj3);
}
}
class PrivateClass {
private PrivateClass() {
System.out.println("私有构造方法执行");
}
@Override
public String toString() {
return "PrivateClass实例";
}
}
3. 调用方法
import java.lang.reflect.*;
public class InvokeMethodExample {
public static void main(String[] args) throws Exception {
Class<?> clazz = Class.forName("java.lang.String");
Object str = "Hello World";
// 调用公共方法
Method lengthMethod = clazz.getMethod("length");
int length = (int) lengthMethod.invoke(str);
System.out.println("长度: " + length);
// 调用带参数的方法
Method charAtMethod = clazz.getMethod("charAt", int.class);
char c = (char) charAtMethod.invoke(str, 0);
System.out.println("第一个字符: " + c);
// 调用静态方法
Method valueOfMethod = clazz.getMethod("valueOf", int.class);
String result = (String) valueOfMethod.invoke(null, 123);
System.out.println("valueOf: " + result);
// 调用私有方法
Class<?> personClass = Person.class;
Person person = new Person("Alice", 25);
Method privateMethod = personClass.getDeclaredMethod("privateMethod");
privateMethod.setAccessible(true);
privateMethod.invoke(person);
// 获取所有方法
System.out.println("所有方法:");
for (Method method : personClass.getDeclaredMethods()) {
System.out.println(" " + method.getName());
}
}
}
class Person {
private String name;
private int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
private void privateMethod() {
System.out.println("私有方法执行");
}
public String getName() { return name; }
public int getAge() { return age; }
@Override
public String toString() {
return "Person{name='" + name + "', age=" + age + "}";
}
}
4. 访问字段
import java.lang.reflect.*;
public class AccessFieldExample {
public static void main(String[] args) throws Exception {
Class<?> clazz = Student.class;
Student student = new Student("Alice", 20, 3.8);
// 获取公共字段
Field nameField = clazz.getField("name");
System.out.println("name: " + nameField.get(student));
// 获取私有字段
Field ageField = clazz.getDeclaredField("age");
ageField.setAccessible(true);
System.out.println("age: " + ageField.get(student));
// 修改字段值
ageField.set(student, 21);
System.out.println("修改后age: " + ageField.get(student));
// 获取所有字段
System.out.println("所有字段:");
for (Field field : clazz.getDeclaredFields()) {
System.out.println(" " + field.getName() + " (" + field.getType().getSimpleName() + ")");
}
}
}
class Student {
public String name;
private int age;
protected double gpa;
public Student(String name, int age, double gpa) {
this.name = name;
this.age = age;
this.gpa = gpa;
}
@Override
public String toString() {
return "Student{name='" + name + "', age=" + age + ", gpa=" + gpa + "}";
}
}
5. 动态代理
import java.lang.reflect.*;
// 接口
interface UserService {
void save(String name);
void delete(String name);
}
// 实现类
class UserServiceImpl implements UserService {
@Override
public void save(String name) {
System.out.println("保存用户: " + name);
}
@Override
public void delete(String name) {
System.out.println("删除用户: " + name);
}
}
// 动态代理处理器
class LogHandler implements InvocationHandler {
private Object target;
public LogHandler(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("方法调用前: " + method.getName());
long start = System.currentTimeMillis();
Object result = method.invoke(target, args);
long end = System.currentTimeMillis();
System.out.println("方法调用后: " + method.getName() + " 耗时: " + (end - start) + "ms");
return result;
}
}
public class DynamicProxyExample {
public static void main(String[] args) {
UserService realService = new UserServiceImpl();
// 创建动态代理
UserService proxyService = (UserService) Proxy.newProxyInstance(
realService.getClass().getClassLoader(),
realService.getClass().getInterfaces(),
new LogHandler(realService)
);
// 使用代理
proxyService.save("Alice");
proxyService.delete("Bob");
}
}
6. 实际应用示例
依赖注入框架
import java.lang.reflect.*;
import java.util.*;
public class SimpleDI {
private Map<Class<?>, Object> instances = new HashMap<>();
public <T> void register(Class<T> clazz) throws Exception {
T instance = clazz.getDeclaredConstructor().newInstance();
instances.put(clazz, instance);
// 注入依赖
for (Field field : clazz.getDeclaredFields()) {
if (field.isAnnotationPresent(Inject.class)) {
Class<?> fieldType = field.getType();
Object dependency = instances.get(fieldType);
if (dependency == null) {
register(fieldType);
dependency = instances.get(fieldType);
}
field.setAccessible(true);
field.set(instance, dependency);
}
}
}
public <T> T getInstance(Class<T> clazz) {
return clazz.cast(instances.get(clazz));
}
}
@interface Inject {}
// 使用示例
class Repository {
public void save(String data) {
System.out.println("保存数据: " + data);
}
}
class Service {
@Inject
private Repository repository;
public void process(String data) {
repository.save(data);
}
}
class Controller {
@Inject
private Service service;
public void handleRequest(String data) {
service.process(data);
}
}
public class DIExample {
public static void main(String[] args) throws Exception {
SimpleDI di = new SimpleDI();
di.register(Repository.class);
di.register(Service.class);
di.register(Controller.class);
Controller controller = di.getInstance(Controller.class);
controller.handleRequest("测试数据");
}
}
7. 最佳实践
- 缓存反射信息:Class、Method、Field对象应该缓存
- 使用setAccessible:访问私有成员时使用
- 处理异常:反射操作可能抛出多种异常
- 性能考虑:反射比直接调用慢,必要时缓存
- 安全限制:注意安全管理器的限制
总结
反射是Java中强大的特性,它提供了动态操作类和对象的能力。掌握反射的使用,可以实现框架设计、依赖注入、动态代理等高级功能。在实际编程中,要合理使用反射,注意性能和安全问题。