Java反射

Java反射机制深度解析:动态编程的强大武器

什么是反射?

Java反射(Reflection)是Java语言的一个强大特性,它允许程序在运行时检查和修改类、方法、字段等结构的行为。简单来说,反射就是"程序能够观察和修改自身行为"的能力。

反射的核心类

Java反射API主要包含以下几个核心类:

  • Class - 代表类的实体
  • Field - 代表类的成员变量
  • Method - 代表类的方法
  • Constructor - 代表类的构造方法
  • Modifier - 提供对修饰符的访问

获取Class对象的三种方式

// 方式1:通过类名.class
Class<?> clazz1 = String.class;

// 方式2:通过对象.getClass()
String str = "Hello";
Class<?> clazz2 = str.getClass();

// 方式3:通过Class.forName()
Class<?> clazz3 = Class.forName("java.lang.String");

反射的基本操作

1. 获取类的信息

public class ReflectionDemo {
    public static void main(String[] args) throws Exception {
        Class<?> clazz = Class.forName("java.util.ArrayList");
        
        // 获取类名
        System.out.println("类名: " + clazz.getName());
        System.out.println("简单类名: " + clazz.getSimpleName());
        
        // 获取包名
        System.out.println("包名: " + clazz.getPackage().getName());
        
        // 获取修饰符
        int modifiers = clazz.getModifiers();
        System.out.println("修饰符: " + Modifier.toString(modifiers));
        
        // 获取父类
        System.out.println("父类: " + clazz.getSuperclass().getName());
        
        // 获取实现的接口
        Class<?>[] interfaces = clazz.getInterfaces();
        for (Class<?> interfaceClass : interfaces) {
            System.out.println("接口: " + interfaceClass.getName());
        }
    }
}

2. 操作字段(Field)

public class FieldDemo {
    private String privateField = "私有字段";
    public String publicField = "公有字段";
    
    public static void main(String[] args) throws Exception {
        Class<?> clazz = FieldDemo.class;
        FieldDemo instance = new FieldDemo();
        
        // 获取所有字段(包括私有字段)
        Field[] fields = clazz.getDeclaredFields();
        for (Field field : fields) {
            System.out.println("字段名: " + field.getName());
            System.out.println("字段类型: " + field.getType().getName());
            
            // 设置可访问性(对于私有字段)
            field.setAccessible(true);
            
            // 获取字段值
            Object value = field.get(instance);
            System.out.println("字段值: " + value);
            
            // 修改字段值
            if (field.getName().equals("privateField")) {
                field.set(instance, "修改后的私有字段");
            }
        }
        
        System.out.println("修改后的privateField: " + instance.privateField);
    }
}

3. 操作方法(Method)

public class MethodDemo {
    private void privateMethod(String message) {
        System.out.println("私有方法被调用: " + message);
    }
    
    public void publicMethod(int number) {
        System.out.println("公有方法被调用: " + number);
    }
    
    public static void main(String[] args) throws Exception {
        Class<?> clazz = MethodDemo.class;
        MethodDemo instance = new MethodDemo();
        
        // 获取所有方法
        Method[] methods = clazz.getDeclaredMethods();
        for (Method method : methods) {
            System.out.println("方法名: " + method.getName());
            System.out.println("返回类型: " + method.getReturnType().getName());
            
            // 获取参数类型
            Class<?>[] paramTypes = method.getParameterTypes();
            for (Class<?> paramType : paramTypes) {
                System.out.println("参数类型: " + paramType.getName());
            }
            
            // 调用方法
            method.setAccessible(true);
            if (method.getName().equals("privateMethod")) {
                method.invoke(instance, "Hello Reflection");
            } else if (method.getName().equals("publicMethod")) {
                method.invoke(instance, 42);
            }
        }
    }
}

4. 操作构造方法(Constructor)

public class ConstructorDemo {
    private String name;
    private int age;
    
    public ConstructorDemo() {
        this.name = "默认名称";
        this.age = 0;
    }
    
    public ConstructorDemo(String name, int age) {
        this.name = name;
        this.age = age;
    }
    
    public static void main(String[] args) throws Exception {
        Class<?> clazz = ConstructorDemo.class;
        
        // 获取所有构造方法
        Constructor<?>[] constructors = clazz.getDeclaredConstructors();
        for (Constructor<?> constructor : constructors) {
            System.out.println("构造方法: " + constructor.getName());
            
            // 获取参数类型
            Class<?>[] paramTypes = constructor.getParameterTypes();
            for (Class<?> paramType : paramTypes) {
                System.out.println("参数类型: " + paramType.getName());
            }
        }
        
        // 使用无参构造方法创建实例
        Constructor<?> defaultConstructor = clazz.getDeclaredConstructor();
        ConstructorDemo instance1 = (ConstructorDemo) defaultConstructor.newInstance();
        System.out.println("无参构造实例: " + instance1.name + ", " + instance1.age);
        
        // 使用有参构造方法创建实例
        Constructor<?> paramConstructor = clazz.getDeclaredConstructor(String.class, int.class);
        ConstructorDemo instance2 = (ConstructorDemo) paramConstructor.newInstance("张三", 25);
        System.out.println("有参构造实例: " + instance2.name + ", " + instance2.age);
    }
}

反射的常见应用场景

1. 动态代理

interface UserService {
    void addUser(String name);
    void deleteUser(String name);
}

class UserServiceImpl implements UserService {
    public void addUser(String name) {
        System.out.println("添加用户: " + name);
    }
    
    public void deleteUser(String name) {
        System.out.println("删除用户: " + name);
    }
}

class DynamicProxyHandler implements InvocationHandler {
    private Object target;
    
    public DynamicProxyHandler(Object target) {
        this.target = target;
    }
    
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("方法调用前: " + method.getName());
        Object result = method.invoke(target, args);
        System.out.println("方法调用后: " + method.getName());
        return result;
    }
}

public class DynamicProxyDemo {
    public static void main(String[] args) {
        UserService realService = new UserServiceImpl();
        
        UserService proxy = (UserService) Proxy.newProxyInstance(
            UserService.class.getClassLoader(),
            new Class[]{UserService.class},
            new DynamicProxyHandler(realService)
        );
        
        proxy.addUser("Alice");
        proxy.deleteUser("Bob");
    }
}

2. 注解处理器

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@interface Loggable {
    String value() default "";
}

class AnnotationProcessor {
    public void processAnnotations(Object obj) throws Exception {
        Class<?> clazz = obj.getClass();
        Method[] methods = clazz.getDeclaredMethods();
        
        for (Method method : methods) {
            if (method.isAnnotationPresent(Loggable.class)) {
                Loggable annotation = method.getAnnotation(Loggable.class);
                String message = annotation.value();
                
                System.out.println("执行带注解的方法: " + method.getName());
                if (!message.isEmpty()) {
                    System.out.println("注解信息: " + message);
                }
                
                method.invoke(obj);
            }
        }
    }
}

class TestClass {
    @Loggable("这是一个测试方法")
    public void testMethod() {
        System.out.println("测试方法被执行");
    }
    
    public void normalMethod() {
        System.out.println("普通方法被执行");
    }
}

3. 配置文件驱动的对象创建

public class ConfigDrivenFactory {
    public static Object createObject(String className) throws Exception {
        Class<?> clazz = Class.forName(className);
        return clazz.getDeclaredConstructor().newInstance();
    }
    
    public static Object createObject(String className, Object... args) throws Exception {
        Class<?> clazz = Class.forName(className);
        Class<?>[] paramTypes = new Class[args.length];
        
        for (int i = 0; i < args.length; i++) {
            paramTypes[i] = args[i].getClass();
        }
        
        Constructor<?> constructor = clazz.getDeclaredConstructor(paramTypes);
        return constructor.newInstance(args);
    }
}

反射的性能考虑

反射虽然强大,但也有一些性能开销:

  1. 性能开销:反射调用比直接调用慢
  2. 安全性限制:需要处理安全检查
  3. 代码可读性:反射代码相对难以理解
  4. 类型安全:编译时类型检查较弱

性能优化建议

public class ReflectionPerformance {
    // 缓存Method对象以避免重复查找
    private static final Map<String, Method> methodCache = new HashMap<>();
    
    public static Object invokeCachedMethod(Object obj, String methodName, Object... args) 
            throws Exception {
        String key = obj.getClass().getName() + "#" + methodName;
        Method method = methodCache.get(key);
        
        if (method == null) {
            Class<?>[] paramTypes = new Class[args.length];
            for (int i = 0; i < args.length; i++) {
                paramTypes[i] = args[i].getClass();
            }
            method = obj.getClass().getDeclaredMethod(methodName, paramTypes);
            method.setAccessible(true);
            methodCache.put(key, method);
        }
        
        return method.invoke(obj, args);
    }
}

反射的最佳实践

  1. 适度使用:只在真正需要动态性时使用反射
  2. 缓存结果:缓存Class、Method、Field等对象
  3. 异常处理:妥善处理各种反射异常
  4. 安全性:注意访问控制和安全限制
  5. 文档注释:为反射代码添加详细注释

总结

Java反射是一个强大的工具,它为Java程序提供了运行时 introspection 和 manipulation 的能力。虽然反射带来了性能开销和复杂性,但在框架开发、动态代理、注解处理等场景中,它是不可或缺的。

关键要点:

  • 反射允许程序在运行时检查类和对象
  • 可以动态调用方法、访问字段、创建实例
  • 广泛应用于框架、代理、注解处理等场景
  • 需要注意性能优化和安全性
  • 适度使用,避免过度复杂化代码

掌握反射机制,将让你在Java开发中拥有更强大的武器,能够编写出更加灵活和动态的应用程序。

posted @ 2025-09-04 08:38  路口偶然遇见你  阅读(18)  评论(0)    收藏  举报