面向对象编程:反射(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. 代码复杂:可读性比直接调用差

相关推荐
斯维赤1 小时前
每天学习一个小算法:快速排序
java·python·学习·算法·排序算法
天码-行空1 小时前
深入拆解 Tomcat 系统架构:连接器如何设计
java·系统架构·tomcat
程序员牛奶1 小时前
Project Loom:让 Java 高并发变得更简单
java·后端
NE_STOP1 小时前
Redis--简介及配置文件详解
java
XiYang-DING2 小时前
【Java EE】volatile关键字
java·单例模式·java-ee
A_aspectJ2 小时前
Java开发的学习优势:稳定基石与多元可能并存的技术赛道
java·开发语言
云烟成雨TD2 小时前
Spring AI Alibaba 1.x 系列【36】FlowAgent 和 BaseAgent 抽象类
java·人工智能·spring
qq_283720052 小时前
Python 模块精讲:collections —— 高级数据结构深度解析(defaultdict、Counter、deque)
java·开发语言
乐嘉明2 小时前
在线堆文件分析功能
java·ai