获取Class对象

  • Class.forName获取Class对象
  • getClass()方法
  • 直接使用类名+”.class”. 对于基本数据类型, 它们的包装类型拥有一个名为”TYPE”的final静态字段, 指向该基本数据类型对应的Class对象

integer.TYPE 指向 int.class
对于数组类型 可以使用类名+ “[].class”来访问, 如int[].class

拿到Class对象后

  1. 使用newInstance()生成一个实例(需要一个无参构造器)
  2. 使用isInstance(Object)来判断一个对象是否是该类的实例, 语法上等同于instance of 关键字(JIT 优化时会有差别?)
  3. 使用Array.newInstance(Class,int)来构造该类型的数组
  4. 使用getFIelds()/getConstructors()/getMethods() 来访问该类型的成员. 带Declared的方法不会返回父类成员,但是会返回私有成员

拿到类成员后

  • 使用Constructor/Field/Method.setAccessible(true)来绕开Java语言的访问限制(如private).
  • 使用Constructor.newInstance(Object[])来生成该类的实例
  • 使用Field.get/set(Objcet)访问字段
  • 使用Method.invoke(Object, Object[])来调用方法

反射调用栈

默认情况下反射调用为委派实现, 委派给本地实现来进行方法实现来进行方法调用. 在达到阈值超过15次(第15次)委派实现会将委派对象DelegatingMethodAccessorImpl切换至动态实现(自动生成字节码(耗时)), 它将直接使用invoke指令来调用目标方法

反射性能开销原因

  • 不定长参数导致的Object数组
  • 基本数据类型的自己装箱拆箱
  • 方法内联 (将本方法内调用的方法与自己一起编译)