当前位置: 首页 > news >正文

Java反射机制——运行时“透视“类的秘密

一个让我困惑的问题

学Java面向对象时,老师常说:"先定义类,再创建对象,然后调用方法。" 这很合理。
但后来我接触到一些框架(比如Spring、MyBatis),发现它们有个"邪门"的能力:
在运行时,它们能创建一个类的对象、调用它的方法,甚至修改私有字段的值——而这一切,事先根本不知道这个类是什么!

这是怎么做到的?
答案就是 Java反射机制(Reflection)。

二、反射是什么?

一句话概括:在运行时动态地获取类的信息,并操作类或对象的能力。
正常写代码时,类的结构在编译期就确定了:

Student s = new Student(); // 编译时就知道有 Student 类 s.study(); // 编译时就知道有 study() 方法

但反射不一样,它让程序在运行时才决定去操作哪个类:

// 运行时才知道要操作 "Student" 这个类 Class<?> clazz = Class.forName("com.example.Student"); // 运行时才知道要调用 "study" 这个方法 Method method = clazz.getMethod("study"); method.invoke(clazz.newInstance());

三、反射的核心API

Java的反射API主要集中在 java.lang.reflect 包下,核心就四个类:

作用
Class代表一个类的"元信息",是反射的入口
Field代表类的成员变量
Method代表类的方法
Constructor代表类的构造方法

四、实战:用反射"解剖"一个类

假设我们有一个普通的类:

public class Person { private String name; public int age; public Person() {} private Person(String name) { this.name = name; } public void sayHello() { System.out.println("Hello, I'm " + name); } private void secret() { System.out.println("This is private!"); } }
  1. 获取Class对象的三种方式
// 方式1:类名.class(最常用,编译期检查) Class<Person> clazz1 = Person.class; // 方式2:对象.getClass()(已有对象时用) Person p = new Person(); Class<? extends Person> clazz2 = p.getClass(); // 方式3:Class.forName()(动态加载,最灵活) Class<?> clazz3 = Class.forName("com.example.Person");
  1. 获取构造方法并创建对象
// 获取所有 public 构造方法 Constructor<?>[] constructors = clazz.getConstructors(); // 获取指定构造方法(包括 private) Constructor<Person> privateCon = clazz.getDeclaredConstructor(String.class); privateCon.setAccessible(true); // 暴力破解访问权限! Person p = privateCon.newInstance("Alice");
  1. 获取并调用方法
// 获取 public 方法(包括继承的) Method sayHello = clazz.getMethod("sayHello"); sayHello.invoke(p); // 输出: Hello, I'm Alice // 获取 private 方法 Method secret = clazz.getDeclaredMethod("secret"); secret.setAccessible(true); secret.invoke(p); // 输出: This is private!
  1. 获取并修改字段
// 获取 public 字段 Field ageField = clazz.getField("age"); ageField.set(p, 20); System.out.println(p.age); // 20 // 获取 private 字段 Field nameField = clazz.getDeclaredField("name"); nameField.setAccessible(true); nameField.set(p, "Bob");

五、反射到底有什么用?

光会API不够,要知道什么时候用。反射的典型应用场景:

  1. 框架开发(Spring、MyBatis、JUnit)
    Spring 的依赖注入(DI)就是靠反射实现的:
// Spring 读取配置文件后,大概是这样创建对象的: Class<?> beanClass = Class.forName("com.example.UserService"); Object bean = beanClass.newInstance(); // 然后反射调用 set 方法注入依赖 Method setDao = beanClass.getMethod("setUserDao", UserDao.class); setDao.invoke(bean, new UserDao());
  1. 动态代理(AOP的基础)
    JDK动态代理底层就是反射:
InvocationHandler handler = (proxy, method, args) -> { System.out.println("方法 " + method.getName() + " 被调用了"); return method.invoke(target, args); };
  1. 序列化与反序列化
    JSON库(如Gson、Jackson)通过反射读取对象的字段,自动完成对象和JSON字符串的转换。
  2. 热加载与插件化
    运行时从外部加载类文件,实现不重启程序更新功能。

六、反射的"代价"

反射很强大,但也有明显的缺点

缺点说明
性能损耗反射调用比直接调用慢10~100倍(JVM难以优化)
安全性问题setAccessible(true) 可以访问私有成员,破坏封装
编译期检查失效反射调用的方法名写错了,编译不会报错,运行时才抛异常
代码可读性差一堆字符串硬编码,IDE无法跳转,维护困难

使用建议:框架底层可以用,业务代码尽量别用。如果非用不可,做好缓存(Method、Field 对象可以复用)。

七、一个有趣的实验

用反射来"打破"String的不可变性:

String s = "Hello"; Field valueField = String.class.getDeclaredField("value"); valueField.setAccessible(true); char[] value = (char[]) valueField.get(s); value[0] = 'h'; // 改成小写 System.out.println(s); // 输出: hello (理论上,但现代JDK有优化可能不生效)
http://www.jsqmd.com/news/1087623/

相关文章:

  • 终极指南:如何免费解锁WeMod专业版并实现手机远程控制游戏
  • 如何在5分钟内配置好DamaiHelper大麦抢票脚本:从零开始的完整教程
  • 如何免费突破百度网盘限速?终极直链解析工具完整指南
  • 从零手写神经网络:理解前向传播与反向传播的数学本质
  • RA8D1 SCI中断与LIN通信实战:从原理到避坑指南
  • OpenRA 2026 测试版发布:新随机地图生成器等多方面更新!
  • 终极指南:5分钟掌握7-Zip免费压缩软件的高效使用技巧
  • 终极指南:5分钟让Switch手柄在PC上完美工作
  • 单片机接口防护:TVS与ESD二极管的实战选型与应用
  • ChatGPT入门≠复制粘贴:20年NLP专家验证的“思维建模法”——让AI真正听懂你的真实意图(附训练日志样本)
  • Chrome插件开发实战:构建Anti-honeypot蜜罐检测工具
  • MoE混合专家架构原理与工程实践:解密大模型稀疏激活机制
  • Obsidian Pandoc终极指南:3分钟掌握文档格式转换神器
  • RVC-WebUI语音克隆实战:从零构建专业级AI语音转换系统
  • 深度解析MPV播放器配置:5个专业级画质优化与性能调优方案
  • 动态二进制翻译与混合执行架构的性能优化实践
  • 企业微信API开发时客户删除事件,业务系统应该如何处理
  • 软考2026新增“云原生开发工程师”科目详解:从大纲变动、实操占比到企业认可度的7维评估
  • Notepad--:跨平台文本编辑器的完整中文解决方案指南
  • 2026封神!5款AI论文平台实测,告别卡壳症,初稿思路秒打通!
  • 引产算生过一胎吗?引产、人流、药流区别
  • GPT-4稀疏激活真相:万亿参数MoE的动态路由与工程落地
  • 中兴光猫配置加解密工具:5分钟掌握网络配置管理核心技术
  • ClickHouse 用 Rust 重写 WAL - G 推 WAL - RUS:内存消耗降超 70%,兼容现有部署
  • ROFLPlayer:英雄联盟回放文件终极查看与分析工具指南
  • AI 具身智能机器人进入家庭的四层技术架构与分阶段落地方案
  • Nginx SSL模块缺失报错解决:从诊断到编译配置全流程
  • Java毕业设计-基于 SpringBoot+Vue 的网络投票管理系统的设计与实现 基于前后端分离的在线投票平台(源码+LW+部署文档+全bao+远程调试+代码讲解等)
  • 从零搭建轻量级Web UI自动化测试框架:Selenium+TestNG+POM实战指南
  • 瑞萨RH850汽车MCU开发板硬件设计解析:从电源管理到通信接口