Java反射机制

面向对象程序设计(Java)

掌握动态编程,提升代码灵活性

为什么需要反射

理解反射,首先要明白它解决了什么实际问题。让我们从几个"要是能这样就好了"的需求场景开始:

反射需求场景

🤔 场景1:插件系统的困境

需求:我想开发一个图片处理软件,用户可以动态加载新的滤镜插件,而不用重新编译主程序。

// 😿 传统方式的问题
public class ImageProcessor {
    public void applyFilter(String filterName) {
        if (filterName.equals("blur")) {
            new BlurFilter().apply(image);
        } else if (filterName.equals("sharpen")) {
            new SharpenFilter().apply(image);
        } else if (filterName.equals("sepia")) {
            new SepiaFilter().apply(image);
        }
        // 每增加一个滤镜都要修改这里!!!
    }
}

要是能这样就好了:根据配置文件中的类名,动态创建对应的滤镜对象...

🤔 场景2:通用工具类的挑战

需求:我想写一个通用的Bean复制工具,自动复制两个相同属性的对象。

💡 小知识:什么是 Java Bean?(点击展开)
Java Bean 是一种标准的 Java 类,通常用于封装数据。它遵循特定规范:
  • 所有属性为 private
  • 提供公共的 getter/setter 方法
  • 有一个无参构造器
  • 实现了 Serializable 接口(可选)
// 😿 传统方式的限制
public class BeanUtils {
    public void copyUser(User source, User target) {
        target.setName(source.getName());
        target.setAge(source.getAge());
        target.setEmail(source.getEmail());
        // 每个类都要写一个复制方法!!!
    }

    public void copyProduct(Product source, Product target) {
        target.setName(source.getName());
        target.setPrice(source.getPrice());
        target.setStock(source.getStock());
        // 又要写一个重复的方法!!!
    }
}

要是能这样就好了:自动扫描所有字段,动态复制属性值...

🤔 场景3:配置驱动的应用

需求:我想根据配置文件决定使用哪个数据库驱动,不用重新编译代码。

// 😿 硬编码的数据库连接
public class DatabaseManager {
    public Connection getConnection() {
        // 驱动类名写死了,切换数据库要改代码!!!
        if ("mysql".equals(config.getDatabase())) {
            return new MySQLConnection();
        } else if ("oracle".equals(config.getDatabase())) {
            return new OracleConnection();
        }
    }
}

要是能这样就好了:根据配置中的完整类名,动态加载驱动类...

反射的价值:让程序具备了"自我认知"能力,在运行时动态调整行为,真正实现了代码的灵活性和可扩展性。这就是为什么所有现代Java框架都离不开反射的原因。

反射概述

Java反射(Reflection)是Java语言的动态特性,允许程序在运行时检查类结构和操作对象。

反射提供了"自省"能力,让程序能够"看到"自身的结构。

反射

✅ 反射可以做什么

  • 检查类结构:获取类的构造方法、字段、方法、注解等元信息
  • 动态创建对象:在运行时创建任意类的实例
  • 动态调用方法:调用任意对象的任意方法(包括私有方法)
  • 读写字段值:获取或设置对象的字段值(包括私有字段)
  • 修改final字段:通过setAccessible突破final限制
  • 创建动态代理:实现AOP、拦截器等功能

❌ 反射不能做什么

  • 不能修改类结构:不能添加/删除方法、字段、构造器
  • 不能改变方法实现:不能修改已有方法的代码逻辑
  • 不能改变继承关系:不能修改类的父类或实现接口
  • 不能修改常量值:无法修改static final基本类型常量
  • 不能修改字节码:需要使用字节码操作库(如ASM、CGLIB)

重要提示:反射只能操作"已有的东西",不能创造"新的东西"。如果需要修改类结构,需要字节码增强技术。

🔧 应用场景

  • 框架开发:Spring、Hibernate等框架的核心机制
  • 工具开发:IDE调试工具、代码生成器
  • 动态配置:插件系统、模块化架构
  • 序列化/反序列化:JSON、XML处理

反射是Java高级特性的重要组成部分,是理解和掌握现代Java框架的基础。

Class对象:反射的入口

Class类是反射机制的入口(注意C大写),每个类在JVM中都有唯一的Class对象。获取Class对象是使用反射的第一步。

每个类只有一个Class对象

🚪 获取Class对象的三种方式

public class ReflectionDemo {
    public static void main(String[] args) throws Exception {
        // 方式1:通过类字面量(推荐),比如这里的 String.class 就是
        Class<String> 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());

        // 验证是同一个Class对象
        System.out.println(clazz1 == clazz2); // true
        System.out.println(clazz2 == clazz3); // true
    }
}

📊 Class对象的基本信息

public static void analyzeClass(Class<?> clazz) {
    System.out.println("类名: " + clazz.getName());
    System.out.println("简单类名: " + clazz.getSimpleName());
    System.out.println("包名: " + clazz.getPackage().getName());
    System.out.println("父类: " + clazz.getSuperclass().getName());
    System.out.println("是否为接口: " + clazz.isInterface());
    System.out.println("是否为数组: " + clazz.isArray());
    System.out.println("是否为基本类型: " + clazz.isPrimitive());
}

获取Class对象后,就可以通过它访问类的所有信息,为后续的反射操作奠定基础。

构造方法:动态创建对象

通过反射可以获取类的构造方法,并使用这些构造方法创建对象实例。Constructor类代表了类的构造方法。

🔍 获取构造方法

import java.lang.reflect.Constructor;
import java.util.ArrayList;

public class ConstructorDemo {
    public static void main(String[] args) throws Exception {
        Class<ArrayList> clazz = ArrayList.class;

        // 获取所有public构造方法
        Constructor<?>[] constructors = clazz.getConstructors();
        System.out.println("ArrayList的构造方法:");
        for (Constructor<?> constructor : constructors) {
            System.out.println(constructor);
        }

        // 获取指定参数类型的构造方法
        Constructor<ArrayList> constructor =
            clazz.getConstructor(int.class); // ArrayList(int initialCapacity)

        System.out.println("指定构造方法: " + constructor);
    }
}

🏗️ 通过构造方法创建对象

public class ObjectCreationDemo {
    public static void main(String[] args) throws Exception {
        Class<String> clazz = String.class;

        // 获取String(byte[], String)构造方法
        Constructor<String> constructor =
            clazz.getConstructor(byte[].class, String.class);

        // 准备构造参数
        byte[] bytes = "Hello 反射".getBytes("UTF-8");
        String charsetName = "UTF-8";

        // 创建对象实例
        String str = constructor.newInstance(bytes, charsetName);
        System.out.println("创建的字符串: " + str);

        // 使用无参构造方法
        Constructor<String> defaultConstructor =
            clazz.getConstructor();
        String emptyStr = defaultConstructor.newInstance();
        System.out.println("空字符串: '" + emptyStr + "'");
    }
}

⚡ 处理构造异常

try {
    Constructor<String> constructor = String.class.getConstructor(int.class);
    String str = constructor.newInstance(100); // 不存在此构造方法
} catch (NoSuchMethodException e) {
    System.out.println("找不到指定的构造方法");
} catch (InstantiationException e) {
    System.out.println("实例化失败");
} catch (IllegalAccessException e) {
    System.out.println("访问权限不足");
} catch (InvocationTargetException e) {
    System.out.println("构造方法抛出异常: " + e.getCause());
}

通过构造方法创建对象是反射的核心功能之一,它让程序能够在运行时动态创建任意类的实例。

字段:访问和修改对象属性

Field类代表类的字段(成员变量),通过反射可以获取和设置任意对象的字段值,包括私有字段。

🔍 获取字段信息

import java.lang.reflect.Field;

public class FieldInfoDemo {
    public static void main(String[] args) {
        Class<String> clazz = String.class;

        // 获取所有public字段(包括继承的)
        Field[] publicFields = clazz.getFields();
        System.out.println("String类的public字段:");
        for (Field field : publicFields) {
            System.out.println("  " + field.getType().getSimpleName() +
                             " " + field.getName());
        }

        // 获取所有声明的字段(包括私有字段)
        Field[] declaredFields = clazz.getDeclaredFields();
        System.out.println("\nString类声明的所有字段:");
        for (Field field : declaredFields) {
            System.out.println("  修饰符: " + field.getModifiers() +
                             ", 类型: " + field.getType().getSimpleName() +
                             ", 名称: " + field.getName());
        }
    }
}

🎯 获取和设置字段值

class Person {
    private String name = "张三";
    public int age = 25;
    protected boolean active = true;
}

public class FieldAccessDemo {
    public static void main(String[] args) throws Exception {
        Person person = new Person();
        Class<?> clazz = person.getClass();

        // 访问public字段
        Field ageField = clazz.getField("age");
        int age = (Integer) ageField.get(person);
        System.out.println("年龄: " + age);

        ageField.set(person, 26);
        System.out.println("修改后年龄: " + person.age);

        // 访问private字段(需要突破访问限制)
        Field nameField = clazz.getDeclaredField("name");
        nameField.setAccessible(true); // 关键!取消访问检查
        String name = (String) nameField.get(person);
        System.out.println("姓名: " + name);

        nameField.set(person, "李四");
        System.out.println("修改后姓名: " + nameField.get(person));
    }
}

🔓 字段修饰符分析

import java.lang.reflect.Modifier;

public static void analyzeField(Field field) {
    int modifiers = field.getModifiers();

    System.out.println("字段: " + field.getName());
    System.out.println("  是否为public: " + Modifier.isPublic(modifiers));
    System.out.println("  是否为private: " + Modifier.isPrivate(modifiers));
    System.out.println("  是否为protected: " + Modifier.isProtected(modifiers));
    System.out.println("  是否为static: " + Modifier.isStatic(modifiers));
    System.out.println("  是否为final: " + Modifier.isFinal(modifiers));
    System.out.println("  是否为volatile: " + Modifier.isVolatile(modifiers));
}

通过反射操作字段可以突破访问限制,但也破坏了封装性。在使用时要谨慎,优先考虑使用公共的getter/setter方法。

方法:动态调用对象行为

Method类代表类的方法,通过反射可以获取方法信息并动态调用任意对象的任意方法。

🔍 获取方法信息

import java.lang.reflect.Method;

public class MethodInfoDemo {
    public static void main(String[] args) {
        Class<String> clazz = String.class;

        // 获取所有public方法(包括继承的)
        Method[] methods = clazz.getMethods();
        System.out.println("String类的public方法数量: " + methods.length);

        // 获取指定名称和参数类型的方法
        try {
            Method substringMethod = clazz.getMethod("substring", int.class, int.class);
            System.out.println("找到方法: " + substringMethod);

            // 获取方法详细信息
            System.out.println("返回类型: " + substringMethod.getReturnType().getSimpleName());
            System.out.println("参数类型: " +
                java.util.Arrays.toString(substringMethod.getParameterTypes()));
            System.out.println("异常类型: " +
                java.util.Arrays.toString(substringMethod.getExceptionTypes()));
        } catch (NoSuchMethodException e) {
            System.out.println("方法不存在");
        }
    }
}

🚀 动态调用方法

public class MethodInvocationDemo {
    public static void main(String[] args) throws Exception {
        String str = "Hello, Java Reflection!";

        // 获取substring方法
        Method substringMethod = String.class.getMethod("substring", int.class, int.class);

        // 动态调用方法
        String result = (String) substringMethod.invoke(str, 7, 11);
        System.out.println("调用结果: " + result); // "Java"

        // 获取length方法
        Method lengthMethod = String.class.getMethod("length");
        int length = (Integer) lengthMethod.invoke(str);
        System.out.println("字符串长度: " + length);

        // 调用静态方法
        Method valueOfMethod = String.class.getMethod("valueOf", int.class);
        String numberStr = (String) valueOfMethod.invoke(null, 123);
        System.out.println("数字转字符串: " + numberStr);
    }
}

🎯 调用私有方法

class SecretService {
    private String secretMethod(String message) {
        return "秘密处理: " + message;
    }

    private static void staticSecret() {
        System.out.println("静态秘密方法被调用");
    }
}

public class PrivateMethodDemo {
    public static void main(String[] args) throws Exception {
        SecretService service = new SecretService();
        Class<?> clazz = service.getClass();

        // 调用私有实例方法
        Method privateMethod = clazz.getDeclaredMethod("secretMethod", String.class);
        privateMethod.setAccessible(true);
        String result = (String) privateMethod.invoke(service, "测试消息");
        System.out.println(result);

        // 调用私有静态方法
        Method privateStaticMethod = clazz.getDeclaredMethod("staticSecret");
        privateStaticMethod.setAccessible(true);
        privateStaticMethod.invoke(null); // 静态方法不需要对象实例
    }
}

⚡ 方法调用异常处理

try {
    Method method = String.class.getMethod("nonExistentMethod");
    method.invoke("test");
} catch (NoSuchMethodException e) {
    System.out.println("方法不存在");
} catch (IllegalAccessException e) {
    System.out.println("访问权限不足");
} catch (InvocationTargetException e) {
    // 获取被调用方法抛出的实际异常
    Throwable actualException = e.getCause();
    System.out.println("方法执行异常: " + actualException.getMessage());
}

动态调用方法是反射最强大的功能之一,它让程序具备了极大的灵活性,是许多框架实现的核心机制。

问题解决 - 插件系统

现在让我们回到第2页提到的那些"要是能这样就好了"的场景,看看如何用反射来优雅地解决这些问题。

✅ 场景1:插件系统的完美实现

public class ImageProcessor {
        // 存储滤镜名称到滤镜类Class对象的映射,而不是存储实例
        private Map<String, Class<? extends Filter>> filterRegistry = new HashMap<>();

        /**
         * 动态注册滤镜
         * @param name 滤镜的别名,如 "blur"
         * @param className 滤镜类的全限定名,如 "com.example.BlurFilter"
         */
        public void registerFilter(String name, String className) {
            try {
                // 1. 动态加载类:在运行时根据字符串名称加载类
                Class<?> clazz = Class.forName(className);

                // 2. 类型检查:确保加载的类实现了Filter接口
                if (Filter.class.isAssignableFrom(clazz)) {
                    // 安全转换并存入注册表
                    filterRegistry.put(name, (Class<? extends Filter>) clazz);
                } else {
                    System.out.println("错误:类 " + className + " 未实现 Filter 接口");
                }
            } catch (ClassNotFoundException e) {
                // 处理类不存在的情况,避免程序崩溃
                System.out.println("滤镜类不存在: " + className);
            }
        }

        /**
         * 动态应用滤镜
         */
        public void applyFilter(String filterName, Image image) {
            // 从注册表中查找对应的Class对象
            Class<? extends Filter> filterClass = filterRegistry.get(filterName);

            if (filterClass != null) {
                try {
                    // 3. 动态实例化:使用反射创建对象实例
                    // 相当于调用 new BlurFilter(),但更灵活
                    Filter filter = filterClass.getDeclaredConstructor().newInstance();

                    // 4. 方法调用:调用接口方法处理图片
                    filter.apply(image);
                } catch (Exception e) {
                    System.out.println("应用滤镜失败: " + e.getMessage());
                }
            }
        }
    }

    // --- 使用示例 ---
    ImageProcessor processor = new ImageProcessor();

    // 假设这些类名是从配置文件读取的,完全解耦!
    processor.registerFilter("blur", "com.example.BlurFilter");
    processor.registerFilter("sharpen", "com.example.SharpenFilter");

    // 动态加载并应用新滤镜,无需修改 ImageProcessor 的任何代码!
    // 这就是"开闭原则"的完美体现:对扩展开放,对修改关闭。
    processor.applyFilter("blur", image);
    processor.applyFilter("sharpen", image);

🎉 解决方案优势:新增滤镜只需要实现Filter接口,无需修改ImageProcessor代码!

问题解决 - Bean复制工具

继续用反射解决实际问题:如何用一个通用方法处理所有类型的对象属性复制?

✅ 场景2:通用Bean复制工具

public class UniversalBeanUtils {
        /**
         * 通用对象属性复制工具
         * 只要字段名和类型相同,就可以跨类复制数据
         * @param source 数据源对象
         * @param target 目标对象
         */
        public static void copyProperties(Object source, Object target) {
            // 1. 获取元数据:得到两个对象的Class对象
            Class<?> sourceClass = source.getClass();
            Class<?> targetClass = target.getClass();

            // 2. 遍历源对象的所有字段(包括私有字段)
            for (Field sourceField : sourceClass.getDeclaredFields()) {
                try {
                    // 3. 查找目标:在目标类中查找是否存在同名字段
                    // 如果找不到会抛出 NoSuchFieldException
                    Field targetField = targetClass.getDeclaredField(sourceField.getName());

                    // 4. 匹配校验:检查两个字段的类型是否完全一致
                    if (targetField.getType().equals(sourceField.getType())) {
                        // 5. 暴力反射:强制设置为可访问,突破 private 限制
                        sourceField.setAccessible(true);
                        targetField.setAccessible(true);

                        // 6. 读写操作:
                        // 读取源对象的字段值
                        Object value = sourceField.get(source);
                        // 写入到目标对象
                        targetField.set(target, value);
                    }
                } catch (Exception e) {
                    // 忽略目标类不存在该字段或类型不匹配的情况,继续处理下一个字段
                }
            }
        }
    }

    // --- 使用示例:一个方法处理所有类型的对象!---

    // 场景 A:同类对象复制(如从数据库实体复制到DTO)
    User user1 = new User("张三", 25, "zhang@example.com");
    User user2 = new User();
    // 自动将 user1 的数据搬运到 user2,无需一个个调用 getter/setter
    UniversalBeanUtils.copyProperties(user1, user2);

    // 场景 B:不同类但有相同字段的对象复制
    Product product1 = new Product("iPhone", 5999, 100);
    ProductDTO productDTO = new ProductDTO();
    // 只要有 name 和 price 字段且类型一致,就能自动复制!
    UniversalBeanUtils.copyProperties(product1, productDTO);

🎉 解决方案优势:一个通用方法处理所有类型,代码复用率极大提升!

问题解决 - 配置驱动应用

✅ 场景3:动态数据库配置

// 数据库驱动接口
public interface DatabaseDriver {
    Connection getConnection(String url, String username, String password);
}

// MySQL 驱动实现
public class MySQLDriver implements DatabaseDriver {
    public Connection getConnection(String url, String username, String password) {
        System.out.println("使用 MySQL 驱动连接数据库...");
        return DriverManager.getConnection(url, username, password);
    }
}

// Oracle 驱动实现
public class OracleDriver implements DatabaseDriver {
    public Connection getConnection(String url, String username, String password) {
        System.out.println("使用 Oracle 驱动连接数据库...");
        return DriverManager.getConnection(url, username, password);
    }
}

public class DatabaseManager {
    /**
     * 根据配置动态创建数据库驱动
     * @param driverClassName 驱动类的全限定名,如 "com.example.MySQLDriver"
     * @return 数据库驱动实例
     */
    public DatabaseDriver createDriver(String driverClassName) {
        try {
            // 1. 动态加载类:根据配置文件中的类名加载
            Class<?> clazz = Class.forName(driverClassName);

            // 2. 类型检查:确保加载的类实现了 DatabaseDriver 接口
            if (DatabaseDriver.class.isAssignableFrom(clazz)) {
                // 3. 动态实例化:创建驱动对象
                return (DatabaseDriver) clazz.getDeclaredConstructor().newInstance();
            } else {
                throw new RuntimeException("类 " + driverClassName + " 未实现 DatabaseDriver 接口");
            }
        } catch (ClassNotFoundException e) {
            throw new RuntimeException("驱动类不存在: " + driverClassName, e);
        } catch (Exception e) {
            throw new RuntimeException("创建驱动失败", e);
        }
    }

    /**
     * 获取数据库连接
     */
    public Connection getConnection(String driverClassName, String url, 
                                    String username, String password) {
        DatabaseDriver driver = createDriver(driverClassName);
        return driver.getConnection(url, username, password);
    }
}

// --- 配置文件 config.properties ---
// database.driver=com.example.MySQLDriver
// database.url=jdbc:mysql://localhost:3306/mydb
// database.username=root
// database.password=123456

// --- 使用示例 ---
public class Application {
    public static void main(String[] args) throws IOException {
        Properties config = new Properties();
        config.load(new FileInputStream("config.properties"));

        DatabaseManager dbManager = new DatabaseManager();

        // 从配置文件读取驱动类名,动态加载!
        String driverClassName = config.getProperty("database.driver");
        String url = config.getProperty("database.url");
        String username = config.getProperty("database.username");
        String password = config.getProperty("database.password");

        // 获取数据库连接,切换数据库只需修改配置文件,无需改代码!
        Connection conn = dbManager.getConnection(driverClassName, url, username, password);

        // 使用数据库连接...
    }
}

🎉 解决方案优势:切换数据库只需修改配置文件,完全解耦!符合开闭原则,扩展性强。

* 补充:Optional 与“显式缺失”

Optional 不是“更高级的 null”,它的目标是:让你在 API 层面显式表达“可能没有值”,并引导调用方做处理。

常用链式写法

import java.util.Optional;

public class OptionalDemo {
    static Optional<String> findNickname(long userId) {
        return userId == 1 ? Optional.of("Tom") : Optional.empty();
    }

    public static void main(String[] args) {
        String name = findNickname(2)
                .map(String::trim)
                .filter(s -> !s.isEmpty())
                .orElse("Anonymous");

        System.out.println(name);
    }
}

三条误区(很重要)

  • 不要用 Optional.get() 当“无脑取值”,那等于把异常推迟
  • 不要在字段里声明 Optional(多数场景更推荐字段允许为 null 或用空对象)
  • orElse(x) 会先计算 x;懒加载请用 orElseGet(() -> x)
String v = Optional.of("ok")
        .orElseGet(() -> expensiveCompute());

把 Optional 当成“返回值的协议”,而不是“到处替换 null 的新类型”。

* 补充:动态代理(Dynamic Proxy)

动态代理让你在运行时“生成一个实现接口的对象”,把方法调用转交给 InvocationHandler,典型用途就是:日志、权限、事务、重试、耗时统计(AOP 的基础之一)。

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

interface Service {
    String hello(String name);
}

final class RealService implements Service {
    public String hello(String name) {
        return "Hello, " + name;
    }
}

public class ProxyDemo {
    public static void main(String[] args) {
        Service target = new RealService();

        InvocationHandler h = (Object proxy, Method method, Object[] a) -> {
            long t0 = System.nanoTime();
            try {
                return method.invoke(target, a);
            } finally {
                long cost = System.nanoTime() - t0;
                System.out.println(method.getName() + " cost(ns)=" + cost);
            }
        };

        Service proxy = (Service) Proxy.newProxyInstance(
                Service.class.getClassLoader(),
                new Class[]{Service.class},
                h
        );

        System.out.println(proxy.hello("Java"));
    }
}
  • 限制:JDK 动态代理只能代理接口;要代理类通常需要字节码增强(例如 CGLIB 思路)
  • 关键点:proxy 不是 target,它只是把调用“转发+增强”

理解动态代理后,你会更容易理解 Spring 的 AOP、拦截器链、以及很多框架的“自动增强”。

反射的优缺点与使用建议

反射机制虽然强大,但也需要在合适的场景下使用。了解其优缺点和适用场景非常重要。

✅ 优点

🔧 极大灵活性:运行时动态创建对象、调用方法,无需在编译时确定类型

🔗 降低耦合度:通过接口和反射实现插件化架构,提高代码的可扩展性

🛠️ 框架支持:Spring、Hibernate等现代框架依赖反射实现IoC、AOP等特性

📊 工具开发:IDE调试器、代码生成器、序列化工具的基础

❌ 缺点

🐌 性能开销:反射操作比直接调用慢10-100倍,不适合高频调用场景

🔓 破坏封装:可以访问私有成员,违反面向对象设计原则

⚠️ 安全风险:绕过访问控制可能导致安全漏洞

📖 代码可读性:反射代码复杂,难以理解和维护

🚫 编译时检查:错误只能在运行时发现,失去编译时类型安全

⚡ 性能优化建议

  • 缓存反射对象:将Class、Method、Field对象缓存起来重复使用
  • 减少反射调用:在性能敏感的代码中避免频繁使用反射
  • 考虑替代方案:接口、回调、设计模式等往往比反射更合适
  • 使用MethodHandle:Java 7+的MethodHandle性能优于传统反射

💡 最佳实践总结

  1. 优先选择编译时确定的方法,只有在真正需要动态性时才使用反射
  2. 在框架和工具中使用反射,在业务逻辑中谨慎使用
  3. 做好异常处理,反射操作容易抛出各种异常
  4. 考虑安全性,避免在生产环境中随意突破访问控制
  5. 做好性能测试,确保反射不会成为性能瓶颈

反射是Java强大的高级特性,要在合适的场景下合理使用。掌握了反射,就掌握了Java动态编程的核心能力。

1 / 15