问题:
- Java 的函数反射性能真的差吗?
- Java 实现反射的方式?
Java 的函数评估反射性能问题之前,首先先了解java中的反射方式。
此为Java method 的源码,其关键实现为 sun.reflect.MethodAccessor
类继承关系
DelegatingMethodAccessorImpl 采用委托形式实现,其本身不包含业务逻辑
class DelegatingMethodAccessorImpl extends MethodAccessorImpl {
private MethodAccessorImpl delegate;
DelegatingMethodAccessorImpl(MethodAccessorImpl delegate) {
setDelegate(delegate);
}
public Object invoke(Object obj, Object[] args)
throws IllegalArgumentException, InvocationTargetException
{
return delegate.invoke(obj, args);
}
void setDelegate(MethodAccessorImpl delegate) {
this.delegate = delegate;
}
}
Java 正常情况 反射执行首先采用native 方式,然儿 java在此做了优化,如下
Native 相对来说 依赖于jni 来执行,相对原生的java 性能较差,故在常用的要反射执行的函数默认前16次执行 采用 native 方式。后java 为其动态生成反射执行类
Arthas 反射运行代码
sc sun.reflect.MethodAccessor
查看所有子类
[arthas@25904]$ sc sun.reflect.MethodAccessor
sun.reflect.DelegatingMethodAccessorImpl
sun.reflect.GeneratedMethodAccessor1
sun.reflect.GeneratedMethodAccessor10
....
sun.reflect.GeneratedMethodAccessor65
查看java 生成的代理类源码
/*
* Decompiled with CFR.
*
* Could not load the following classes:
* pook.action.logic.simple.MciLogicController
* pook.action.msg.request.simple.MciGameProgressLogRequest
*/
package sun.reflect;
import java.lang.reflect.InvocationTargetException;
import pook.action.logic.simple.MciLogicController;
import pook.action.msg.request.simple.MciGameProgressLogRequest;
import sun.reflect.MethodAccessorImpl;
public class GeneratedMethodAccessor86
extends MethodAccessorImpl {
/*
* Loose catch block
* Enabled aggressive block sorting
* Enabled unnecessary exception pruning
* Enabled aggressive exception aggregation
* Lifted jumps to return sites
*/
public Object invoke(Object object, Object[] arrobject) throws InvocationTargetException {
if (object == null) {
throw new NullPointerException();
}
MciLogicController mciLogicController = (MciLogicController)object;
if (arrobject.length != 1) {
throw new IllegalArgumentException();
}
MciGameProgressLogRequest mciGameProgressLogRequest = (MciGameProgressLogRequest)arrobject[0];
try {
mciLogicController.mciGameProgressLogLogic(mciGameProgressLogRequest);
return null;
}
catch (Throwable throwable) {
throw new InvocationTargetException(throwable);
}
catch (ClassCastException | NullPointerException runtimeException) {
throw new IllegalArgumentException(super.toString());
}
}
}
前期函数反射执行 采用jni 方式相对性能低于原生的 java调用方式,后期使用动态生成的java 去执行,无异于原生方式执行。
3. 为什么第一次就采用动态生成代理类?
代理类的的生成相对较耗时,而在大多数的反射执行仅为一两次,故费时生成代理类得不偿失。
4. Java 生成代理类的次数可以动态设置吗?
可以。手动指定 sun.reflect.noInflation 可以自行修改