← 返回首页
🪞

Java反射机制详解:动态类加载与方法调用

📂 java ⏱ 4 min 779 words

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. 最佳实践

  1. 缓存反射信息:Class、Method、Field对象应该缓存
  2. 使用setAccessible:访问私有成员时使用
  3. 处理异常:反射操作可能抛出多种异常
  4. 性能考虑:反射比直接调用慢,必要时缓存
  5. 安全限制:注意安全管理器的限制

总结

反射是Java中强大的特性,它提供了动态操作类和对象的能力。掌握反射的使用,可以实现框架设计、依赖注入、动态代理等高级功能。在实际编程中,要合理使用反射,注意性能和安全问题。