反射机制在 JVM中

前面博客中说到反射机制,它是Java的重要特性,它允许Java程序在运行的时候观察程序本身,甚至是修改程序。以前说到了Java通过Class枚举获得类中的所有方法,属性值,其实还可以用Method.SetAcessible方法绕过Java语音的访问权限,在私有方法所在类之外的地方调用该方法。

反射最常用的应用是Spring IOC的DI,其实在我们常用的IDE软件中,在我们输入在类名后输入.号后出来的方法提示就是运用了反射。

那具体反射是怎么实现的呢?在查看method.invoke源码后,可以容易发现method.invoke委派给MethodAccessor来处理。MethodAccessor是一个接口,它已经实现了2种方式来完成反射,一个是本地实现,一个是委派调用。

对于委派调用:解释来说就是每一个Method实例的第一次反射都会生成一个委派实现,而委派实现的具体实现就是一个本地实现。对于本地实现:相当于每次进入JVM内部的时候,我们都拥有了Method实例所指向方法的地址,反射调用就是将传入的参数准备好,然后调用进入方法内部。

上面我们说到了委派实现,它具体是有什么功能呢?看完书后,明白,其实JVM的反射调用机制还是用了一个动态调用字节码的机制,它是直接使用invoke来调用目标方法,叫做动态实现。而委派实现的作用就是作为中间层,能使动态实现和本地实现很好的切换。

从开销上来说,如果大规模的反射调用目标方法的话,动态实现的速度是本地实现的20倍以上。但是通常如果在程序中只需要一两次调用的话,本地实现的效率就要好得多。因为动态实现需要实现字节码,那就是一个繁琐的开销。 因此JVM 虚拟机初始化设置了一个阀值 为15次。当调用次数少于15次的时候采用本地实现,但调用大于15次的时候就采用动态实现。

不过总的来说,反射调用都需要去遍历这个目标类,比如getMehtod就需要去要遍历目标类的的所有共有方法,所以对于程序来说都是一个不小的开销。特别是如果方法中有自动封拆箱数据的操作,会导致JVM频繁的发生GC。所以使用反射的时候还是要多考虑考虑开销问题。

猜你喜欢

转载自blog.csdn.net/puzimengya/article/details/81636229