1. Implementation of reflection call
local implementation
package com.sz.simple;
import java.lang.reflect.Method;
public class Test {
public static void target() {
new Exception("#").printStackTrace();
}
public static void main(String[] args) throws Exception {
Test test = new Test();
Class<?> klass = Class.forName("com.sz.simple.Test");
Method method = klass.getMethod("target");
method.invoke(test,null);
}
}
As shown in the above code, when the main method is executed, the bytecode object of the class is first obtained through the fully qualified class name, and then the method object is obtained and then the target method is called and executed reflectively. The stack trace when the print method is executed is shown in the figure below
The reflection class calls the invoke method of the delegated class, then the delegated class calls the invoke method of the local method, and finally executes the target method
Java reflection method -> java delegation method -> c++ local method -> java target method
Since the process from java to c++ method and then to java method is very time-consuming, in addition to delegating to local method implementations, delegating classes can also delegate to dynamic method implementations
Dynamic implementation
Modify the above code to look like this
package com.sz.simple;
import java.lang.reflect.Method;
public class Test {
public static void target(int i) {
new Exception("#"+i).printStackTrace();
}
public static void main(String[] args) throws Exception {
Test test = new Test();
Class<?> klass = Class.forName("com.sz.simple.Test");
for (int i = 0; i < 17; i++) {
Method method = klass.getMethod("target",int.class);
method.invoke(test,i);
}
}
}
java -verbose:class com.sz.simple.Test
Comparing the 15th and 16th prints, you will find that during the 16th execution, the delegation class is delegated to GeneratedMethodAccessor, which adopts dynamic implementation.
We can modify the value of Dsun.reflect.inflationThreshold by modifying the value of 15 dynamically implemented. If your project uses reflection to call methods extensively, and you don’t want to generate a large number of dynamically generated classes, you can set Dsun.reflect.inflationThreshold = int.max
If you don't want to use the local implementation to call the target method, you can add the following parameters when executing
-Dsun.reflect.noInflation=true
2. Implementation efficiency of two reflection calls
Dynamic implementation is 20 times faster than local implementation [2]. This is because the dynamic implementation does not need to switch from Java to C++ and then to Java, but because the generation of bytecode is very time-consuming, if it is called only once, the local implementation is 3 to 4 times faster [3].