java反射
了解反射的原理:
1:反射主要作用就是在不确定对象是否存在的情况下去查找
2:主要有三个对象Class,Field(代表类的成员变量),Method(主要是invoke方法)
3:Method.invoke()方法:
3.1 首先对java.lang.reflect.AccessibleObject#override属性检查(AccessibleObject对象是Field,Method,Constructor 的基类)(主要检查包,类,属性的访问权限,例如private就没有访问权限)
可以通过setAccessible()方法跳过权限检查
3.2 第一次调用通过sun.reflect.ReflectionFactory#newMethodAccessor生成反射对象;通过源码发现MethodAccessor实现有两个版本,一个是Java版本,一个是native版本。
初次启动时Method.invoke()和Constructor.newInstance()方法采用native方法要比Java方法快3-4倍,而启动后native方法又要消耗额外的性能而慢于Java方法。也就是说,Java实现的版本在初始化时需要较多时间,
但长久来说性能较好;native版本正好相反,启动时相对较快,但运行时间长了之后速度就比不过Java版了。
3.3 为了尽可能地减少性能损耗,HotSpot JDK采用“inflation”的技巧:让Java方法在被反射调用时,开头若干次使用native版,
等反射调用次数超过阈值时则生成一个专用的MethodAccessor实现类,生成其中的invoke()方法的字节码,以后对该Java方法的反射调用就会使用Java版本
3.4 研究ReflectionFactory.newMethodAccessor()生产MethodAccessor对象的逻辑,一开始(native版)会生产NativeMethodAccessorImpl和DelegatingMethodAccessorImpl两个对象。但是DelegatingMethodAccessorImpl.java其实只是一个中间层
,方便在native版与Java版的MethodAccessor之间进行切换
3.5 每次NativeMethodAccessorImpl.invoke()方法被调用时,程序调用计数器都会增加1,看看是否超过阈值;一旦超过,则调用MethodAccessorGenerator.generateMethod()来生成Java版的MethodAccessor的实现类,
并且改变DelegatingMethodAccessorImpl所引用的MethodAccessor为Java版。后续经由DelegatingMethodAccessorImpl.invoke()调用到的就是Java版的实现了。
Method,MethodHandle