Method.invoke()本身要用数组包装参数;而且每次调用都必须检查方法的可见性(在Method.invoke()里),也必须检查每个实际参数与形式参数的类型匹配性(在NativeMethodAccessorImpl.invoke0()里或者生成的Java版MethodAccessor.invoke()里);而且Method.invoke()就像是个独木桥一样,各处的反射调用都要挤过去,在调用点上收集到的类型信息就会很乱,影响内联程序的判断,使得Method.invoke()自身难以被内联到调用方。关于反射调用方法的一个logrednaxelafx.iteye.com
关于这个问题,R大在他的ITeyeblog上讲到过
根据这篇文章介绍
每一个Method都有一个root,不暴漏给外部,而是每次copy一个Method。
具体的反射调用逻辑是委托给MethodAccessor的,而accessor对象会在第一次invoke的时候才创建,是一种lazy init方式。而且默认Class类会cache method对象。目前MethodAccessor的实现有两种,通过设置inflation,一个native方式,一种生成java bytecode方式。native方式启动快,但运行时间长了不如java方式,个人感觉应该是java方式运行长了,jit compiler可以进行优化。所以JDK6的实现,在native方式中,有一个计数器,当调用次数达到阀值,就会转为使用java方式。默认值是15。java方式的实现,基本和非反射方式相同。主要影响性能的问题,1是method.invoke中每次都要进行参数数组包装,2.在method.invoke中要进行方法可见性检查,3在accessor的java实现方式下,invoke时会检查参数的类型匹配。而在JDK7中methodhandle来做反射调用,形参和实参是准确的,所以只需要在链接方法的时候做检查,调用时不用再做检查。并且methodhandle是不可变值,所以jvm可以做激进优化,例如内联。