在开源的框架中大多数都很少直接new对象进行使用的,当然其主要是框架,不关心具体的实现业务。反射有自己的好处:
- 使应用更加有扩展性
- 查看类自身的信息,枚举类的成员信息
- 测试工具的使用,写测试代码的时候,提高我们的代码覆盖率
有一个问题,反射调用和直接调用有什么区别呢?
来个案例:
import org.apache.commons.lang3.time.StopWatch;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.concurrent.TimeUnit;
public class RelectionDemo {
/**
* 测试调用方法次数
*/
static int time = 1000000;
public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
reflectionMethod();
callMethod();
}
private static void callMethod() {
RelectionDemo instance = new RelectionDemo();
StopWatch stopWatch = StopWatch.createStarted();
for (int i = 0; i < time; i++) {
String res = instance.hello();
handle(res);
}
stopWatch.stop();
long time = stopWatch.getTime(TimeUnit.MILLISECONDS);
System.out.println("直接调用:" + time + "ms");
}
private static void handle(Object res) {
}
private static void reflectionMethod() throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
Method hello = RelectionDemo.class.getDeclaredMethod("hello");
RelectionDemo instance = new RelectionDemo();
StopWatch stopWatch = StopWatch.createStarted();
for (int i = 0; i < time; i++) {
Object invoke = hello.invoke(instance);
handle(invoke);
}
stopWatch.stop();
long time = stopWatch.getTime(TimeUnit.MILLISECONDS);
System.out.println("反射调用:" + time + "ms");
}
public String hello(){
return "hello";
}
}
反射调用:36ms
直接调用:8ms
从直观结果上来看,肯定是反射更慢了一些,那么反射为什么会比较慢呢?
原因
1 反射的整个过程都是需要开发者自己手动写的东西,调用什么类的什么方法,都要说明清楚,有一定可能性会写错,方法名写错,参数写错什么的,所以内部的实现肯定会进行参数校验。相比于直接的调用某个方法,这时虚拟机已经知道对象是什么,要调用哪个方法,也不用检测,所以反射调用会多出来参数校验的过程。
- 校验可见性
- 检验权限
2 无法被JIT优化,JIT可以帮助java的字节码到原生的机器码层面上,这样的话减少了java字节码的再解析操作,而反射方法是无法被jit优化的。
3 调用过程中的封装与解封操作,invoke 方法的参数是 Object[] 类型,在调用的时候需要进行一次封装。产生了额外的开销。
最后
记录一个细节性的问题,之前只是知道反射比较慢,也没有深究过为什么会慢,学习不能想当然,还是要多追问自己为什么。
参考: