面向对象编程:反射(Reflection)原理与应用详解

面向对象编程:反射(Reflection)原理与应用详解

反射是面向对象编程中非常核心的高级特性 ,它的本质是:程序在运行时,可以动态获取类的完整信息(成员变量、方法、构造器、注解等),并且能动态调用对象的方法、操作成员变量

简单说:正常编程是「写死代码调用类」,反射是「运行时才知道要操作哪个类,动态调用」


一、反射的核心原理

1. 核心前提:Class 类

Java 中一切皆对象,类本身也是对象 ,每个类被加载到 JVM 后,都会生成一个唯一的 Class 对象,这个对象里保存了类的所有信息:

  • 类名、父类、实现的接口
  • 成员变量(Field)
  • 成员方法(Method)
  • 构造方法(Constructor)
  • 注解、修饰符等

反射就是通过这个 Class 对象,反向获取类信息、反向调用类功能,所以叫「反射」。

2. 反射的工作流程

  1. 获取 Class 对象:拿到类的「元数据」入口
  2. 解析类信息:获取变量、方法、构造器等
  3. 动态操作:创建对象、调用方法、修改变量(无视权限修饰符)

3. 核心特点

运行时动态操作 :编译时不需要知道目标类,运行时才确定

无视访问权限 :可以调用 private 方法、修改 private 变量

解耦 :降低代码耦合,提高灵活性

性能较低 :比直接调用慢

破坏封装:绕过了访问控制,可能破坏代码安全性


二、反射的核心 API(Java 版)

Java 反射的核心类都在 java.lang.reflect 包下:

  1. Class:代表一个类,反射的入口
  2. Field:代表类的成员变量
  3. Method:代表类的成员方法
  4. Constructor:代表类的构造方法

三、反射应用实战举例

我们用一个简单的实体类,演示反射的5大最常用场景

第一步:定义测试类

java 复制代码
public class User {
    // 私有成员变量
    private Long id;
    public String username;

    // 无参构造
    public User() {}

    // 有参构造
    public User(Long id, String username) {
        this.id = id;
        this.username = username;
    }

    // 私有方法
    private void privateMethod(String msg) {
        System.out.println("私有方法被调用:" + msg);
    }

    // 公共方法
    public void publicMethod() {
        System.out.println("公共方法被调用");
    }

    // getter/setter
    public Long getId() { return id; }
    public void setId(Long id) { this.id = id; }
    public String getUsername() { return username; }
    public void setUsername(String username) { this.username = username; }
}

场景1:获取 Class 对象(反射入口)

3种标准方式:

java 复制代码
public class ReflectTest {
    public static void main(String[] args) throws ClassNotFoundException {
        // 方式1:Class.forName(全类名) → 最常用(配置文件/框架底层)
        Class<?> clazz1 = Class.forName("com.example.User");

        // 方式2:类名.class
        Class<User> clazz2 = User.class;

        // 方式3:对象.getClass()
        User user = new User();
        Class<? extends User> clazz3 = user.getClass();
    }
}

场景2:反射创建对象

java 复制代码
// 1. 获取 Class 对象
Class<User> clazz = User.class;

// 2. 调用无参构造创建对象(核心)
User user = clazz.newInstance(); // 旧版
// 新版推荐:
User user1 = clazz.getDeclaredConstructor().newInstance();
System.out.println(user1); // 输出:User@xxx

// 3. 调用有参构造创建对象
Constructor<User> constructor = clazz.getConstructor(Long.class, String.class);
User user2 = constructor.newInstance(1L, "反射测试");
System.out.println(user2.getUsername()); // 输出:反射测试

场景3:反射操作成员变量(包括 private)

java 复制代码
User user = new User();
Class<?> clazz = user.getClass();

// 1. 获取 public 变量
Field usernameField = clazz.getField("username");
usernameField.set(user, "张三"); // 赋值
System.out.println(user.getUsername()); // 输出:张三

// 2. 获取 private 变量(必须开启暴力反射)
Field idField = clazz.getDeclaredField("id");
idField.setAccessible(true); // 取消访问检查
idField.set(user, 100L); // 赋值
System.out.println(user.getId()); // 输出:100

场景4:反射调用成员方法(包括 private)

java 复制代码
User user = new User();
Class<?> clazz = user.getClass();

// 1. 调用 public 无参方法
Method publicMethod = clazz.getMethod("publicMethod");
publicMethod.invoke(user); // 输出:公共方法被调用

// 2. 调用 private 有参方法
Method privateMethod = clazz.getDeclaredMethod("privateMethod", String.class);
privateMethod.setAccessible(true); // 暴力反射
privateMethod.invoke(user, "我是反射调用的"); // 输出:私有方法被调用:我是反射调用的

场景5:动态获取类的全部信息

java 复制代码
Class<User> clazz = User.class;

// 获取类名
System.out.println("全类名:" + clazz.getName());
System.out.println("简类名:" + clazz.getSimpleName());

// 获取所有方法
Method[] methods = clazz.getDeclaredMethods();
for (Method method : methods) {
    System.out.println("方法名:" + method.getName());
}

// 获取所有变量
Field[] fields = clazz.getDeclaredFields();
for (Field field : fields) {
    System.out.println("变量名:" + field.getName());
}

四、反射的实际业务/框架应用

反射不是为了日常业务代码写的 ,而是框架、中间件、工具类的底层核心技术,几乎所有主流框架都依赖反射:

1. Spring 框架(最经典)

  • Spring IOC:读取 XML/注解配置的类名,用反射创建 Bean 对象
  • Spring MVC:通过反射调用 Controller 里的请求方法
  • AOP:动态代理 + 反射实现方法增强

2. 序列化/反序列化

  • JSON 框架(Jackson、Gson、Fastjson):
    不需要写 getter/setter,反射读取对象变量 → 转 JSON
    JSON → 反射赋值给对象变量

3. 通用工具类

  • 通用对象拷贝工具(BeanUtils.copyProperties)
  • 通用 Excel 导入导出工具
  • 通用参数校验工具

4. 注解解析

  • 自定义注解生效:反射获取类/方法上的注解,执行对应逻辑

5. 配置驱动开发

  • 读取配置文件中的类全限定名,反射实例化对象(无需硬编码)

五、反射的优缺点总结

优点

  1. 动态性:运行时才确定类,代码灵活、可配置
  2. 解耦:减少硬编码,提高扩展性
  3. 无视权限:框架底层需要操作私有成员

缺点

  1. 性能差:比直接调用慢,不适合高频调用
  2. 安全风险:破坏封装,可访问私有成员
  3. 代码复杂:可读性比直接调用差

相关推荐
大圣编程9 小时前
面向对象深度理解
java·开发语言·算法
影寂ldy10 小时前
C# const 常量 / readonly 只读 / static readonly
java·开发语言·c#
摇滚侠10 小时前
Maven 入门+高深 体系外 jar 包导入 172
java·maven·jar
做个文艺程序员10 小时前
第02篇:K8s 存储与配置管理:ConfigMap、Secret、PV/PVC 实战——Java SaaS 多租户配置最佳实践
java·容器·kubernetes
爱吃牛肉的大老虎10 小时前
Spring中用到的设计模式
java·spring·设计模式
Refrain_zc10 小时前
Android TV 语音消息实战:遥控器 PCM 录音失真修复与扬声器强制播放方案
java
Stick_ZYZ10 小时前
从“能调用工具”到“能稳定执行任务”:Agent 工程化的下一步
java·人工智能·后端·spring·ai
代码中介商10 小时前
C++四大设计模式:单例、工厂、观察者、策略
java·c++·设计模式
宋志宗10 小时前
从三层架构到清晰边界:一套更适合复杂 Java 服务的分层方法
java
lulu121654407810 小时前
Codex Computer Use 深度分析:AI桌面自动化的技术突破与行业影响
java·运维·人工智能·自动化·ai编程