(6)Method的invoke方法解析
2018-10-06 本文已影响0人
Mrsunup
网上有一遍文章讲解得比较深入也比较详细,地址如下:https://www.cnblogs.com/onlywujun/p/3519037.html
我这边就简单演示一下,invoke的调用链过程 ,先准备演示类:
public class A {
public void foo(String name) {
System.out.println("Hello, " + name);
}
}
public class TestClassLoad {
public static void main(String[] args) throws Exception {
Class<?> clz = Class.forName(A.class.getName());
Object o = clz.newInstance();
Method m = clz.getMethod("foo", String.class);
for (int i = 0; i < 16; i++) {
if(i==15){
m.invoke(o, Integer.toString(i));
}else{
m.invoke(o, Integer.toString(i));
}
}
}
}
在控制台加上-XX:+TraceClassLoading的参数 ,运行
image.png
[Loaded java.lang.Void from C:\Program Files\Java\jdk1.8.0_92\jre\lib\rt.jar]
[Loaded com.java.reflect.invoke.A from file:/D:/Eclipse2018Data/personProject/jdk/java-lang-reflect/target/classes/]
Hello, 0
Hello, 1
Hello, 2
Hello, 3
Hello, 4
Hello, 5
Hello, 6
Hello, 7
Hello, 8
Hello, 9
Hello, 10
Hello, 11
Hello, 12
Hello, 13
Hello, 14
[Loaded sun.reflect.ClassFileConstants from C:\Program Files\Java\jdk1.8.0_92\jre\lib\rt.jar]
[Loaded sun.reflect.AccessorGenerator from C:\Program Files\Java\jdk1.8.0_92\jre\lib\rt.jar]
[Loaded sun.reflect.MethodAccessorGenerator from C:\Program Files\Java\jdk1.8.0_92\jre\lib\rt.jar]
[Loaded sun.reflect.ByteVectorFactory from C:\Program Files\Java\jdk1.8.0_92\jre\lib\rt.jar]
[Loaded sun.reflect.ByteVector from C:\Program Files\Java\jdk1.8.0_92\jre\lib\rt.jar]
[Loaded sun.reflect.ByteVectorImpl from C:\Program Files\Java\jdk1.8.0_92\jre\lib\rt.jar]
[Loaded sun.reflect.ClassFileAssembler from C:\Program Files\Java\jdk1.8.0_92\jre\lib\rt.jar]
[Loaded sun.reflect.UTF8 from C:\Program Files\Java\jdk1.8.0_92\jre\lib\rt.jar]
[Loaded sun.reflect.Label from C:\Program Files\Java\jdk1.8.0_92\jre\lib\rt.jar]
[Loaded sun.reflect.Label$PatchInfo from C:\Program Files\Java\jdk1.8.0_92\jre\lib\rt.jar]
[Loaded sun.reflect.MethodAccessorGenerator$1 from C:\Program Files\Java\jdk1.8.0_92\jre\lib\rt.jar]
[Loaded sun.reflect.ClassDefiner from C:\Program Files\Java\jdk1.8.0_92\jre\lib\rt.jar]
[Loaded sun.reflect.ClassDefiner$1 from C:\Program Files\Java\jdk1.8.0_92\jre\lib\rt.jar]
[Loaded sun.reflect.GeneratedMethodAccessor1 from __JVM_DefineClass__]
Hello, 15
[Loaded java.lang.Shutdown from C:\Program Files\Java\jdk1.8.0_92\jre\lib\rt.jar]
[Loaded java.lang.Shutdown$Lock from C:\Program Files\Java\jdk1.8.0_92\jre\lib\rt.jar]
主要看Loaded sun.reflect.GeneratedMethodAccessor1 这一句,表示在invoke调用15次之后用了jdk自带的方法生成器来进行调用
invoke 调用是由MethodAccessor来进行调用的,而具体的NativeMethodAccessorImpl和DelegatingMethodAccessorImpl是由ReflectionFactory创建而来的,DelegatingMethodAccessorImpl这里是一个委托,会把调用链关系转换为NativeMethodAccessorImpl的invoke方法进行调用
public MethodAccessor newMethodAccessor(Method var1) {
checkInitted();
if (noInflation && !ReflectUtil.isVMAnonymousClass(var1.getDeclaringClass())) {
return (new MethodAccessorGenerator()).generateMethod(var1.getDeclaringClass(), var1.getName(), var1.getParameterTypes(), var1.getReturnType(), var1.getExceptionTypes(), var1.getModifiers());
} else {
NativeMethodAccessorImpl var2 = new NativeMethodAccessorImpl(var1);
DelegatingMethodAccessorImpl var3 = new DelegatingMethodAccessorImpl(var2);
var2.setParent(var3);
return var3;
}
}
而NativeMethodAccessorImpl的invoke方法如下,默认调用的是本地的invoke0方法,但是会有一个调用次数的判断,如果调用次数大于15,则由MethodAccessorGenerator生成方法的MethodAccessorImpl的实现,然后改变DelegatingMethodAccessorImpl的委托类设置为jdk生成方法访问器
,则调用次数大于15的时候是由jdk的生成方法访问器进行方法调用的
public Object invoke(Object var1, Object[] var2) throws IllegalArgumentException, InvocationTargetException {
if (++this.numInvocations > ReflectionFactory.inflationThreshold() && !ReflectUtil.isVMAnonymousClass(this.method.getDeclaringClass())) {
MethodAccessorImpl var3 = (MethodAccessorImpl)(new MethodAccessorGenerator()).generateMethod(this.method.getDeclaringClass(), this.method.getName(), this.method.getParameterTypes(), this.method.getReturnType(), this.method.getExceptionTypes(), this.method.getModifiers());
this.parent.setDelegate(var3);
}
return invoke0(this.method, var1, var2);
}
private static native Object invoke0(Method var0, Object var1, Object[] var2);