0
点赞
收藏
分享

微信扫一扫

Java反射机制探秘

一叶轻舟okok 2022-05-01 阅读 69

文章目录

概述

赋予了我们在运行时分析类以及执行类中方法的能力。通过反射你可以获取任意一个类的所有属性和方法,你还可以调用这些方法和属性。

反射

本质其实就是根据 符号 拿到符号表以及直接地址 进行调用。

反射调用的实现原理

public final class Method extends Executable {
  ...
  public Object invoke(Object obj, Object... args) throws ... {
    ... // 权限检查
    MethodAccessor ma = methodAccessor;
    if (ma == null) {
      ma = acquireMethodAccessor();
    }
    return ma.invoke(obj, args);
  }
}
  • 委派给了 MethodAccessor 接口实现,
  • MethodAccessor 接口提供了两种实现,一种是本地方法实现,另一种是 Java 实现

那么如何拿到执行地址呐?有两种方式:
在这里插入图片描述
考虑到许多反射调用仅会执行一次,Java 虚拟机设置了一个阈值 15(可以通过 -Dsun.reflect.inflationThreshold= 来调整),当某个反射调用的调用次数在 15 之下时,采用本地实现;当达到 15 时,便开始动态生成字节码,并将委派实现的委派对象切换至动态实现,这个过程我们称之为 Inflation。

反射调用的开销

  1. 变长参数方法导致的 Object 数组
    • 由于 Method.invoke 是一个变长参数方法,在字节码层面它的最后一个参数会是 Object 数组(。Java 编译器会在方法调用处生成一个长度为传入参数数量的 Object 数组,并将传入参数一一存储进该数组中
  2. 基本类型的自动装箱、拆箱
    • 由于 Object 数组不能存储基本类型,Java 编译器会对传入的基本类型参数进行自动装箱
  3. 最重要的方法内联
    • 由于 Java 虚拟机的关于上述调用点的类型 profile(注:对于 invokevirtual 或者 invokeinterface,Java 虚拟机会记录下调用者的具体类型,我们称之为类型 profile)无法同时记录这么多个类,因此可能造成所测试的反射调用没有被内联的情况

参考

JVM系列之:JVM是如何实现反射的

举报

相关推荐

0 条评论