这里有新鲜出炉的 Java 函数式编程,程序狗速度看过来!
Java 程序设计语言
java 是一种可以撰写跨平台应用软件的面向对象的程序设计语言,是由 Sun Microsystems 公司于 1995 年 5 月推出的 Java 程序设计语言和 Java 平台(即 JavaEE(j2ee), JavaME(j2me), JavaSE(j2se))的总称.
这篇文章主要为大家详细介绍了 Java 方法反射的实现原理,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
博主说:Java 反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和属性;这种动态获取信息以及动态调用对象方法的功能称为 Java 语言的反射机制.在本文中,占小狼分析了 Java 反射机制的实现原理(源码),感兴趣的同学可以通过阅读本文花上几分钟了解了解.
正文
方法反射实例
通过 Java 的反射机制,可以在运行期间调用对象的任何方法,如果大量使用这种方式进行调用,会有性能或内存隐患么?为了彻底了解方法的反射机制,只能从底层代码入手啦!
public class ReflectCase {
public static void main(String[] args) throws Exception {
Proxy target = new Proxy();
Method method = Proxy.class.getDeclaredMethod("run");
method.invoke(target);
}
static class Proxy {
public void run() {
System.out.println("run");
}
}
}
Method 获取
调用 Class 类的 getDeclaredMethod 可以获取指定方法名和参数的方法对象 Method.
getDeclaredMethod
其中 privateGetDeclaredMethods 方法从缓存或 JVM 中获取该 Class 中申明的方法列表,searchMethods 方法将从返回的方法列表里找到一个匹配名称和参数的方法对象.
searchMethods
如果找到一个匹配的 Method,则重新复制一份返回,即 Method.copy() 方法.
所次每次调用 getDeclaredMethod 方法返回的 Method 对象其实都是一个新的对象,且新对象的 root 属性都指向原来的 Method 对象,如果需要频繁调用,最好把 Method 对象缓存起来.
privateGetDeclaredMethods
从缓存或 JVM 中获取该 Class 中申明的方法列表,实现如下:
其中 reflectionData() 方法实现如下:
这里有个比较重要的数据结构 ReflectionData,用来缓存从 JVM 中读取类的如下属性数据:
从 reflectionData() 方法实现可以看出:reflectionData 对象是 SoftReference 类型的,说明在内存紧张时可能会被回收,不过也可以通过 - XX:SoftRefLRUPolicyMSPerMB 参数控制回收的时机,只要发生 GC 就会将其回收,如果 reflectionData 被回收之后,又执行了反射方法,那只能通过 newReflectionData 方法重新创建一个这样的对象了,newReflectionData 方法实现如下:
通过 unsafe.compareAndSwapObject 方法重新设置 reflectionData 字段;在 privateGetDeclaredMethods 方法中,如果通过 reflectionData() 获得的 ReflectionData 对象不为空,则尝试从 ReflectionData 对象中获取 declaredMethods 属性,如果是第一次,或则被 GC 回收之后,重新初始化后的类属性为空,则需要重新到 JVM 中获取一次,并赋值给 ReflectionData,下次调用就可以使用缓存数据了.
Method 调用
获取到指定的方法对象 Method 之后,就可以调用它的 invoke 方法了,invoke 实现如下:
应该注意到:这里的 MethodAccessor 对象是 invoke 方法实现的关键,一开始 methodAccessor 为空,需要调用 acquireMethodAccessor 生成一个新的 MethodAccessor 对象,MethodAccessor 本身就是一个接口,实现如下:
在 acquireMethodAccessor 方法中,会通过 ReflectionFactory 类的 newMethodAccessor 创建一个实现了 MethodAccessor 接口的对象,实现如下:
在 ReflectionFactory 类中,有 2 个重要的字段:noInflation(默认 false)和 inflationThreshold(默认 15),在 checkInitted 方法中可以通过 - Dsun.reflect.inflationThreshold=xxx 和 - Dsun.reflect.noInflation=true 对这两个字段重新设置,而且只会设置一次;如果 noInflation 为 false,方法 newMethodAccessor 都会返回 DelegatingMethodAccessorImpl 对象,DelegatingMethodAccessorImpl 的类实现:
其实,DelegatingMethodAccessorImpl 对象就是一个代理对象,负责调用被代理对象 delegate 的 invoke 方法,其中 delegate 参数目前是 NativeMethodAccessorImpl 对象,所以最终 Method 的 invoke 方法调用的是 NativeMethodAccessorImpl 对象 invoke 方法,实现如下:
这里用到了 ReflectionFactory 类中的 inflationThreshold,当 delegate 调用了 15 次 invoke 方法之后,如果继续调用就通过 MethodAccessorGenerator 类的 generateMethod 方法生成 MethodAccessorImpl 对象,并设置为 delegate 对象,这样下次执行 Method.invoke 时,就调用新建的 MethodAccessor 对象的 invoke() 方法了.这里需要注意的是:generateMethod 方法在生成 MethodAccessorImpl 对象时,会在内存中生成对应的字节码,并调用 ClassDefiner.defineClass 创建对应的 Class 对象,实现如下:
在 ClassDefiner.defineClass 方法实现中,每被调用一次都会生成一个 DelegatingClassLoader 类加载器对象:
这里每次都生成新的类加载器,是为了性能考虑,在某些情况下可以卸载这些生成的类,因为类的卸载是只有在类加载器可以被回收的情况下才会被回收的,如果用了原来的类加载器,那可能导致这些新创建的类一直无法被卸载,从其设计来看本身就不希望这些类一直存在内存里的,在需要的时候有就行啦!
来源: http://www.phperz.com/article/18/0114/352971.html