0
点赞
收藏
分享

微信扫一扫

Java 反射调用与直接调用对比

有点d伤 2021-09-21 阅读 53

在开源的框架中大多数都很少直接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[] 类型,在调用的时候需要进行一次封装。产生了额外的开销。

最后

记录一个细节性的问题,之前只是知道反射比较慢,也没有深究过为什么会慢,学习不能想当然,还是要多追问自己为什么。

参考:

https://juejin.im/post/5da33b2351882509334fc0d3

https://docs.oracle.com/javase/tutorial/reflect/index.html

举报

相关推荐

0 条评论