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

什么是Java反射机制?

一、什么是反射?

反射(Reflection) 是 Java 提供的一种 在运行时动态获取类的信息,并能直接操作类的属性、方法和构造器 的机制。

换句话说:

  • 普通调用:在编译期就已经确定要调用哪个类、哪个方法。

  • 反射调用:程序可以在运行时,通过字符串(类名、方法名)去加载类,并调用其中的方法或访问属性。

Java 中反射的核心类位于 java.lang.reflect 包下,主要包括:

  • Class: 表示类的字节码对象。

  • Method: 表示类的方法。

  • Field: 表示类的成员变量。

  • Constructor: 表示类的构造方法。


二、反射能做什么?

1.获取类的信息

        类的名称、修饰符(public/private 等)、父类、实现的接口。

        类中的字段(Field)、方法(Method)、构造器(Constructor)。

2.操作对象

        动态创建对象(替代new)。

        动态调用对象的方法(即使方法名在编译时未知)。

        动态读取和修改对象的属性(即使是 private)。

3.操作类

        动态加载一个类(通过Class.forName("类的全限定名") )。

        判断一个类是否有特定的注解。

        实现动态代理(Spring、MyBatis 等框架的底层原理)。


三、一个实际示例

假设我们有一个消息服务接口 MessageService,以及两个实现类 EmaliService 和 SmsService 。

接口定义

public interface MessageService {void send(String message);void send(String message, String to);
}

邮件服务实现

public class EmailService implements MessageService{private String fromAddress;public EmailService() {this.fromAddress = "noreply@example.com";}@Overridepublic void send(String message) {System.out.println("发送邮件到默认地址: " + fromAddress + "  内容是: " + message);}@Overridepublic void send(String message, String to) {System.out.println("发送邮件给: " + to + "  内容是: " + message);}
}

短信服务实现


public class SmsService implements MessageService{private String formPhone;public SmsService() {this.formPhone = "12345678901";}@Overridepublic void send(String message) {System.out.println("发送短信: " + message);}@Overridepublic void send(String message, String to) {System.out.println("发送短信: " + to + " 给 " + message);}
}

四、普通调用 vs 反射调用

传统写法(硬编码)

public class MessageTools {public static void main(String[] args) {String config = "EmailService"; // 模拟配置MessageService service = null;if ("EmailService".equals(config)) {service = new EmailService();} else if ("SmsService".equals(config)) {service = new SmsService();}if (service != null) {service.send("Hello World!!!");}}
}

运行结果:

问题:如果新增一个实现类(比如 WeChatService ),必须修改 if / else 并重新编译,扩展性差。


使用反射(动态加载)

import java.lang.reflect.Method;public class MessageTools {public static void main(String[] args) throws Exception {// 模拟配置:通过类全限定名来决定加载哪个类String className = "soft.study.App.EmailService";// 1. 加载类Class<?> clazz = Class.forName(className);// 2. 创建对象Object service = clazz.getDeclaredConstructor().newInstance();// 3. 获取方法Method method = clazz.getMethod("send", String.class);Method method1 = clazz.getMethod("send", String.class, String.class);// 4. 动态调用方法method.invoke(service, "你好!");method1.invoke(service, "你好!", "张三");}
}

运行结果:

优势:如果要替换成 SmsService,只需要修改配置,不需要修改源码。

注意:这里的className 写死了"soft.study.App.EmailService" ,只是为了演示方便

在真实项目中,我们通常通过以下优化方式避免硬编码:


五、反射调用的优化方式

1.使用配置文件

在 config.properties 写入:

message.service.class=soft.study.App.EmailService

程序启动时读取配置:

Properties props = new Properties();
props.load(new FileInputStream("config.properties"));
String className = props.getProperty("message.service.class");

这样切换服务时,只需修改配置文件,无需改源码。


2.使用注解 + 扫描(框架常用方式框架(如 Spring)会通过 反射扫描包路径,自动注册带有 @Service 的类,不需要我们手动指定类名。

@Service("emailService")
public class EmailService implements MessageService { ... }

3.结合工厂模式

工厂模式(Factory Pattern)本身就是为了解决 对象创建与业务逻辑解耦 的问题。
如果把反射和工厂模式结合,就能在保留反射灵活性的同时,让调用方完全不用关心反射的细节。

public class ServiceFactory {public static MessageService create(String type) throws Exception {String className = switch (type) {case "email" -> "soft.study.App.EmailService";case "sms" -> "soft.study.App.SmsService";default -> throw new IllegalArgumentException("未知类型");};return (MessageService) Class.forName(className).getDeclaredConstructor().newInstance();}
}

业务代码只需调用:

MessageService service = ServiceFactory.create("email");
service.send("测试消息");

六、反射在框架中的应用

1.Spring IoC 容器  

        通过反射实例化 Bean,并完成依赖注入。

        @Autowired 注入的原理就是反射 + 注解。

2.MyBatis  

        通过反射读取 Mapper 接口信息,动态生成代理类。

        SQL 执行时反射调用参数的 getter 方法。

3.JPA / Hibernate 

        通过反射获取实体类的字段、注解信息,映射到数据库表。

4.JUnit / 测试框架  

        自动扫描并执行带有 @Test 注解的方法。


七、反射的优缺点

优点

  • 灵活性高:能在运行时动态加载类、调用方法。

  • 解耦:结合配置文件或注解,扩展功能无需修改源码。

  • 功能强大:许多框架(Spring、MyBatis、Hibernate)核心都依赖反射。

缺点

  • 性能损耗:反射调用方法比直接调用慢。

  • 安全风险:可访问 private 属性,破坏封装性。

  • 可读性差:代码不直观,调试和维护困难。


八、总结

         反射机制是 Java 提供的一项底层能力,它允许程序在运行时动态获取类的信息并调用方法。虽然直接在业务代码中频繁使用反射并不推荐,因为会带来一定的性能损耗和可读性问题,但在框架开发中反射却是实现核心功能的基础。例如,Spring 通过反射完成 IoC 容器中的对象实例化和依赖注入,MyBatis 借助反射动态生成 Mapper 的代理对象,Hibernate 依赖反射完成实体类与数据库表的映射。

        在实际开发中,如果只是简单的业务逻辑,直接通过 new 创建对象即可,既高效又清晰;而在需要高扩展性、动态加载或解耦的场景下,反射的优势才会凸显出来。

http://www.dtcms.com/a/434298.html

相关文章:

  • 使用Docker安装Neo4j
  • 建立网站的步骤筝晃湖南岚鸿官网深圳专业建设网站哪个公司好
  • 20软件测试需求分析评审
  • SQL 多表查询实用技巧:ON 和 WHERE 的区别速览
  • 网站备案 内容央企八大设计院
  • 从汇编角度看C++优化:编译器真正做了什么
  • 分布式专题——25 深入理解网络通信和TCP、IP协议
  • UV python多版本管理
  • Schema是什么?
  • 许昌做网站优化wordpress 控制每页显示文章数
  • MAX31865模块和PT100实现温度测量使用配置笔记教程
  • Elasticsearch MCP 服务器:与你的 Index 聊天
  • 【ROS2学习笔记】话题通信篇:话题通信再探
  • 网络编程中“地址重用(SO_REUSEADDR)”
  • 汕头网站建设推广厂家wordpress 响应式图片
  • Rust的错误处理
  • 可视化地图
  • Rust与C接口交互
  • 【C++实战(64)】C++ 邂逅SQLite3:数据库编程实战之旅
  • 泉州网页建站模板开发网址
  • 中华建设杂志网站记者管理网站英文
  • React 18+TS中使用Cesium 1.95
  • View:new关键词干了什么事,还有原型链是什么
  • 如何在新的Spring Boot项目中关闭Spring Security?
  • 药企做网站需要哪些手续国内新闻最新消息今天在线
  • 【Flutter】GetX最佳实践与避坑指南
  • AIFoto 1.15.4 | AI图片工具,AI擦除衣服,变性感衣服
  • 数据合规与ISO标准体系
  • 在Ubuntu22.04系统下安装Jellyfin
  • 福州做网站的app排名优化公司