Java 反射

反射如何在运行时检查与调用成员:能力、成本、封装绕过与框架使用边界。

#type / concept #status / growing #tech / dev #resource / java

[!info] 关联笔记

Java 反射

这个概念为什么出现

框架要在不知道具体类的情况下注入依赖、映射 JSON、调用测试方法。反射提供运行时的类型信息与调用能力,但昂贵且能破坏封装。

[!abstract] 一句话理解 反射通过 Class/Method/Field 在运行时读取结构并调用;适合框架与工具,不适合业务热路径的默认写法。

最小可运行示例

场景:插件式计算器按方法名调用

import java.lang.reflect.Method;

public class ReflectCall {
    public int add(int a, int b) { return a + b; }

    public static void main(String[] args) throws Exception {
        ReflectCall target = new ReflectCall();
        Method m = ReflectCall.class.getMethod("add", int.class, int.class);
        Object result = m.invoke(target, 2, 3);
        System.out.println(result);
    }
}
javac ReflectCall.java && java ReflectCall

期望:

5

结合场景再看三个关注点

  1. 方法查找按名与参数类型
  2. invoke 异常包装InvocationTargetException
  3. 模块强封装可能阻止 setAccessible。

核心概念与准确模型

1. 入口

obj.getClass() / Class.forName / .class

2. 成员访问

getMethod(public)/ getDeclaredMethod(含非 public)

3. 代价

  • 失优化、检查开销
  • 安全与封装风险

边界情况与反直觉行为

  1. 泛型擦除使反射拿不到完整运行时参数类型。
  2. 基本类型与包装类型在 Class 字面量上不同。
  3. 原生镜像/关闭反射配置时失败。

常见误区

[!warning] 常见误区:业务代码遍地反射 优先接口多态与生成代码。

工程实践

  1. 反射集中在框架边界并缓存 Method 句柄。
  2. 考虑 MethodHandle
  3. 明确 opens/exports。
  4. 安全审核 setAccessible。

本节总结

  • 运行时元编程利器
  • 成本与封装代价
  • 框架常用、业务慎用

自测题

  1. getMethod 与 getDeclaredMethod 差别?
  2. 为什么 JSON 库爱反射或代码生成?
参考答案
  1. 前者看 public 成员(含继承);后者看本类声明成员含非 public。
  2. 需要在未知类型上读写属性;生成代码可降运行时成本。

延伸阅读与资料来源

资料类型支撑内容
Reflection Trail教程反射
java.lang.reflectAPI
创建于 2026/7/15 更新于 2026/7/15