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

【Java源码阅读系列55】深度解读Java Method 类源码

Java 的反射机制是其动态特性的重要支撑,而 java.lang.reflect.Method 类则是反射调用方法的核心入口。本文将基于 JDK 1.8 源码,从类结构、关键方法、设计模式、典型场景等维度,深入解析 Method 类的实现逻辑与设计思想。

一、类结构与核心定位

1.1 类定义与继承关系

Method 类被声明为 public final class Method extends Executable,继承自 ExecutableExecutableMethodConstructor 的公共父类,封装了参数、异常等通用逻辑)。作为 final 类,Method 不可被继承,确保反射行为的一致性。

1.2 核心字段:方法元信息的载体

Method 类通过一组私有字段存储方法的元信息,关键字段如下:

  • Class<?> clazz:方法声明所在的类(即 declaring class)。
  • String name:方法名称(如 toString)。
  • Class<?>[] parameterTypes:方法参数类型数组(如 {String.class, int.class})。
  • Class<?> returnType:方法返回类型(如 void.class)。
  • int modifiers:方法修饰符(如 publicstatic,通过 Modifier类解析)。
  • volatile MethodAccessor methodAccessor:方法访问器,实际执行方法调用的代理对象(懒加载创建)。
  • Method root:共享 MethodAccessor 的根对象(通过 copy() 方法创建副本时指向原始对象)。

这些字段完整描述了一个方法的“身份”(声明类、名称、参数)和“行为”(修饰符、返回类型),是反射调用的基础。


二、关键方法深度解析

2.1 invoke(Object obj, Object... args):反射调用的入口

invokeMethod 类最核心的方法,负责通过反射执行目标方法。其源码逻辑可分为三部分:

(1)权限检查

if (!override) {if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) {Class<?> caller = Reflection.getCallerClass();checkAccess(caller, clazz, obj, modifiers);}
}
  • override 标志来自父类 AccessibleObject,若为 false(默认),需检查调用者是否有权限访问目标方法。
  • Reflection.quickCheckMemberAccess 是快速检查(基于类的访问权限),若失败则通过 checkAccess 进行更严格的访问控制(如私有方法需调用 setAccessible(true) 才能访问)。

(2)获取 MethodAccessor

MethodAccessor ma = methodAccessor; // 读取 volatile 变量保证可见性
if (ma == null) {ma = acquireMethodAccessor(); // 懒加载创建
}
  • MethodAccessorsun.reflect 包中的接口,实际由 NativeMethodAccessorImpl(本地实现)或 MethodAccessorImpl(字节码生成实现)提供具体调用逻辑。
  • acquireMethodAccessor 优先从 root 共享的 MethodAccessor 中获取(享元模式),若不存在则通过 reflectionFactory.newMethodAccessor(this) 创建新实例,并同步到 root 链。

(3)执行方法调用

最终通过 ma.invoke(obj, args) 触发实际方法执行,处理参数类型转换(如基本类型自动拆箱)和返回值包装(如 int 转为 Integer)。

2.2 copy():共享资源的副本创建

Method copy() {if (this.root != null) throw new IllegalArgumentException("Can not copy a non-root Method");Method res = new Method(...); // 复制所有元信息res.root = this; // 副本的 root 指向原始对象res.methodAccessor = methodAccessor; // 共享 MethodAccessorreturn res;
}
  • 当通过 Class.getMethod() 等方法获取 Method 实例时,JVM 会创建 copy 副本,避免直接修改原始对象的 accessibility 状态(AccessibleObject 的设计要求)。
  • 通过 root 链共享 MethodAccessor,减少重复创建开销(享元模式的典型应用)。

2.3 isDefault():判断接口默认方法

public boolean isDefault() {return ((getModifiers() & (Modifier.ABSTRACT | Modifier.PUBLIC | Modifier.STATIC)) == Modifier.PUBLIC) && getDeclaringClass().isInterface();
}
  • Java 8 引入的接口默认方法需满足:修饰符为 public(非 abstract、非 static),且声明在接口中。
  • 该方法为框架(如 Spring)判断默认方法提供了依据(例如 AOP 对默认方法的增强)。

三、设计模式分析

3.1 代理模式:MethodAccessor 的解耦设计

MethodAccessor 是典型的代理(Proxy)角色,隐藏了方法调用的底层实现:

  • 本地代理(NativeMethodAccessorImpl):通过 JNI 调用本地方法,适合冷启动或低频调用。
  • 字节码代理(MethodAccessorImpl):通过 sun.reflect.GeneratedMethodAccessor 动态生成字节码(如 UnsafeASM),性能接近直接调用(热点方法优化)。

通过代理模式,Method 类无需关心具体调用实现,只需委托给 MethodAccessor,符合“开闭原则”。

3.2 享元模式:root 链的资源共享

copy() 方法创建的 Method 副本通过 root 字段指向原始对象,共享 methodAccessor。这种设计避免了为每个 Method 实例重复创建 MethodAccessor,减少内存占用和初始化开销,是享元模式(Flyweight)的典型应用。

3.3 工厂模式:泛型信息的懒加载

getGenericInfo() 方法通过工厂模式创建 MethodRepository(泛型信息仓库):

private MethodRepository genericInfo;
@Override
MethodRepository getGenericInfo() {if (genericInfo == null) {genericInfo = MethodRepository.make(getGenericSignature(), getFactory());}return genericInfo;
}
  • CoreReflectionFactory 负责生成 GenericsFactory,用于解析泛型签名(如 List<String>)。
  • 懒加载机制避免了非泛型方法的额外开销,提升了性能。

四、典型场景代码示例

4.1 反射调用普通方法

import java.lang.reflect.Method;public class ReflectionDemo {public static void main(String[] args) throws Exception {// 获取 Method 实例Method toStringMethod = String.class.getMethod("toString");// 调用方法(obj 为 "hello",无参数)String result = (String) toStringMethod.invoke("hello");System.out.println(result); // 输出:hello}
}

4.2 反射调用私有方法

public class PrivateMethodDemo {private void privateMethod(String msg) {System.out.println("Private: " + msg);}public static void main(String[] args) throws Exception {PrivateMethodDemo obj = new PrivateMethodDemo();// 获取私有方法并设置可访问Method privateMethod = PrivateMethodDemo.class.getDeclaredMethod("privateMethod", String.class);privateMethod.setAccessible(true); // 突破访问限制privateMethod.invoke(obj, "Hello Reflection"); // 输出:Private: Hello Reflection}
}

4.3 动态调用接口默认方法(Java 8+)

interface MyInterface {default void defaultMethod() {System.out.println("Default Method");}
}class MyImpl implements MyInterface {}public class DefaultMethodDemo {public static void main(String[] args) throws Exception {MyImpl obj = new MyImpl();Method defaultMethod = MyInterface.class.getMethod("defaultMethod");System.out.println("Is default method: " + defaultMethod.isDefault()); // 输出:truedefaultMethod.invoke(obj); // 输出:Default Method}
}

五、总结与应用场景

5.1 核心价值

Method 类是 Java 反射机制的“方法操作入口”,通过封装方法元信息和代理调用逻辑,为框架和工具提供了动态访问方法的能力。其设计兼顾了灵活性(支持任意方法调用)和性能(通过 MethodAccessor 优化热点调用)。

5.2 典型应用场景

  • 框架开发:Spring 的依赖注入(通过反射调用 setter 方法)、MyBatis 的 SQL 映射(动态调用 Mapper 接口方法)。
  • 工具类库:JSON 序列化(如 Jackson 通过反射读取字段和方法)、日志框架(动态记录方法调用信息)。
  • 测试工具:Mockito 通过反射模拟方法行为(when().thenReturn())。
  • 动态代理:JDK 动态代理基于 InvocationHandler,通过 Method.invoke() 转发方法调用。

5.3 注意事项

  • 性能开销:反射调用比直接调用慢(约 10-100 倍),高频调用场景需谨慎(可通过缓存 Method 实例或使用字节码框架优化)。
  • 访问权限:私有方法需调用 setAccessible(true),但可能被 JVM 安全策略(如 SecurityManager)阻止。
  • 类型安全:反射绕过了编译期类型检查,需手动处理参数类型转换(避免 IllegalArgumentException)。

结语

Method 类是 Java 反射机制的核心组件,其源码中代理模式、享元模式的应用,以及懒加载、权限检查等细节,体现了“灵活与性能”的平衡设计。理解 Method 的实现逻辑,不仅能帮助我们更好地使用反射,也能为框架设计和性能优化提供思路。

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

相关文章:

  • 78、【OS】【Nuttx】【启动】caller-saved 和 callee-saved 示例:栈指针和帧指针(下)
  • 股票行情接口api,板块、概念接口,股票主力资金流接口,板块概念资金流接口
  • 暑期自学嵌入式——Day05(C语言阶段)
  • 1-创建Vue3项目
  • Linux系统编程——进程间通信
  • 融智兴科技: RFID超高频洗涤标签解析
  • LeetCode--48.旋转图像
  • 快速了解网络爬虫
  • 设备驱动的私有数据设计
  • yocto开发(1)----bitbake的全流程分析
  • 指针数组和数组指针的应用案例
  • js对象简介、内置对象
  • 聊聊数据和功能测试面临的挑战有哪些?
  • #systemverilog# 关键字之 变量声明周期与静态方法关系探讨
  • 美团外卖霸王餐接口对接具体操作步骤
  • NW972NW974美光固态闪存NW977NW981
  • 【读论文】AgentOrchestra 解读:LLM 智能体学会「团队协作」去解决复杂任务
  • 海思3516CV610 卷绕 研究
  • JxBrowser 8.9.2 版本发布啦!
  • Python22 —— 标准库(random库)
  • 简单手写一个Spring boot starter
  • flask request实现两台PC之间文件传输通信
  • 华夏基金(ChinaAMC)推出全球首只人民币计价的代币化货币基金
  • AUTOSAR进阶图解==>AUTOSAR_SWS_BusMirroring
  • lombok版本过低导致@SuperBuilder注解编译无法通过(java: 类型变量数目错误; 需要3)
  • Fiddler 中文版在移动开发中的调试应用 从抓包到性能调优
  • CMSIS DSP FFT
  • Linux探秘坊-------15.线程概念与控制
  • 内容安全策略(CSP)详解:Web安全的关键防线
  • SegNet:一种用于图像分割的深度卷积编码器解码器架构