目录

反射机制的理解

反射机制的理解

一、 getName 方法解析
代码功能
public static String getName(String key) throws IOException {
   Properties properties = new Properties();
   FileInputStream in = new FileInputStream("D:\\路径...\\application.properties");
   properties.load(in); // 加载配置文件内容
   in.close(); // 关闭流
   return properties.getProperty(key); // 根据 key 返回对应的值
}
作用

application.properties 配置文件中读取指定 key 的值(如 classNamemethodName )。

配置文件示例

假设 application.properties 内容如下:

# 定义要反射的类名和方法名
className=com.example.TestInvoke
methodName=printMessage
执行过程
  1. 加载文件 :通过 FileInputStream 读取指定路径的配置文件。
  2. 解析配置Properties.load() 方法将文件内容解析为键值对。
  3. 获取值properties.getProperty("className") 返回 "com.example.TestInvoke"
代码问题
  1. 硬编码路径D:\\路径... 是绝对路径,实际项目应使用相对路径或类路径加载。
  2. 资源未安全关闭 :若 load() 抛出异常, in.close() 可能不会执行,建议用 try-with-resources
  3. 异常处理简单 :直接抛出 IOException ,未处理文件不存在等具体问题。
改进版本
public static String getName(String key) {
   // 使用类路径加载(文件需放在 resources 目录下)
   try (InputStream in = YourClass.class.getClassLoader().getResourceAsStream("application.properties")) {
       Properties properties = new Properties();
       properties.load(in);
       return properties.getProperty(key);
  } catch (IOException e) {
       throw new RuntimeException("加载配置文件失败", e);
  }
}

二、反射机制详解
什么是反射?

反射(Reflection)是 Java 在 运行时 动态获取类信息并操作类的能力,包括:

  • 动态加载类
  • 创建对象
  • 调用方法
  • 访问私有成员
为什么需要反射?
  1. 解耦 :代码不直接依赖具体类(如通过配置文件指定类名)。
  2. 灵活性 :框架中自动装配对象(如 Spring 的 @Autowired )。
  3. 通用工具 :如 JSON 序列化、单元测试调用私有方法。

三、结合代码理解反射流程
完整流程
1. 读取配置文件 → 2. 获取类名和方法名 → 3. 反射加载类 → 4. 创建对象 → 5. 调用方法
分步解析
  1. 读取配置 通过 getName("className") 获取 "com.example.TestInvoke"
  2. 加载类
Class  c = Class.forName("com.example.TestInvoke");
  • JVM 动态加载该类到内存(如果尚未加载)。
  1. 创建实例
TestInvoke obj = (TestInvoke) c.newInstance();
  • 相当于执行 new TestInvoke() (要求类有无参构造方法)。
  1. 获取并调用方法
Method method = c.getDeclaredMethod("printMessage");
method.invoke(obj);
  • 即使 printMessage 是私有方法, setAccessible(true) 后仍可调用。

四、反射核心 API
操作API 示例作用
加载类Class.forName("全限定类名")获取类的 Class 对象
创建实例clazz.newInstance()clazz.getConstructor().newInstance()实例化对象
获取方法clazz.getMethod("方法名", 参数类型...)获取公开方法
获取私有方法clazz.getDeclaredMethod("方法名") + setAccessible(true)访问私有方法
调用方法method.invoke(实例对象, 参数...)执行方法

五、示例:从配置到反射的完整过程
1. 配置文件 application.properties
className=com.example.UserService
methodName=login
2. 目标类 UserService
package com.example;
​
public class UserService {
   private void login() {
       System.out.println("用户登录成功!");
  }
}
3. 反射调用代码
public static void main(String[] args) {
   try {
       // 从配置读取类名和方法名
       String className = getName("className"); // "com.example.UserService"
       String methodName = getName("methodName"); // "login"
​
       // 反射操作
       Class  clazz = Class.forName(className);
       Method method = clazz.getDeclaredMethod(methodName);
       method.setAccessible(true);
       Object instance = clazz.getDeclaredConstructor().newInstance();
       method.invoke(instance); // 输出:"用户登录成功!"
  } catch (Exception e) {
       e.printStackTrace();
  }
}

六、反射的注意事项
  1. 性能开销 :反射比直接调用慢,频繁调用需谨慎。
  2. 安全限制 :模块化系统中(Java 9+)可能禁止访问私有成员。
  3. 破坏封装 :反射可以绕过访问修饰符,滥用会导致代码难以维护。
  4. 类型安全 :编译时无法检测类型错误,需自行保证类型正确性。

七、常见应用场景
  1. 框架开发 :如 Spring 的依赖注入、MyBatis 的 Mapper 动态代理。
  2. 动态加载插件 :通过配置文件指定实现类。
  3. 单元测试 :测试私有方法(不推荐,但有时必要)。
  4. 通用工具 :如通过反射实现对象拷贝、序列化工具。

总结
  • 通过 配置文件 解耦了类名和方法名的硬编码,利用 反射 实现了动态调用。
  • 反射是 Java 强大的特性,但需谨慎使用。理解其原理后,可以更深入掌握框架设计思想(如 Spring 的核心机制)。