在写代码的时候,发现从父类类通过getDeclaredMethod获取的方法可以调用子类的对象,而子类改写了这个方法,从子类类通过getDeclaredMethod也能获取到方法,这时去调用父类的对象也会报错。虽然这是很符合多态的现象,也符合java的动态绑定规范,但还是想弄懂java是如何实现的,就学习了下方法的源代码只
方法的调用方法,
<强> 1。先检查,AccessibleObject的覆盖属性是否为真的。强>
AccessibleObject是方法、字段构造函数的父类,覆盖属性默认为假,可调用种setAccessible方法改变,如果设置为真,则表示可以忽略访问权限的限制,直接调用。
2。如果不是真正的,则要进行访问权限检测。用反射的quickCheckMemberAccess方法先检查是不是公共的,如果不是再用Reflection.getCallerClass(1)方法获
得到调用这个方法的类,然后做是否有权限访问的校验,校验之后缓存一次,以便下次如果还是这个类来调用就不用去做校验了,直接用上次的结果,(很奇怪用这种方式缓存,因为这种方式如果下次换个类来调用的话,就不用会缓存了,而再验证一遍,把这次的结果做为缓存,但上一次的缓存结果就被冲掉了。这是一个很简单的缓冲机制,只适用于一个类的重复调用)只
3。调用MethodAccessor的调用方法。每个方法对象包含一个根对象,根对象里持有一个MethodAccessor对象。我们获得的方法独享相当于一个根对象的镜像,所有这类方法共享根里的MethodAccessor对象,(这个对象由ReflectionFactory方法生成,ReflectionFactory对象在类的方法中是static 最后的由本地方法实例化)。
ReflectionFactory生成MethodAccessor:如果noInflation的属性为真则直接返回MethodAccessorGenerator创建的一个MethodAccessor。否则返回DelegatingMethodAccessorImpl,并将他与一个NativeMethodAccessorImpl互相引用。但DelegatingMethodAccessorImpl执行调用方法的时候又委托给NativeMethodAccessorImpl了。
再一步深入
4. nativemethodaccessorimpl的invkoe方法:
调用natiave方法invoke0执行方法调用。
注意这里有一个计数器numInvocations,每调用一次方法+ 1,当比,ReflectionFactory.inflationThreshold(15)大的时候,用MethodAccessorGenerator创建一个MethodAccessor,并把之前的DelegatingMethodAccessorImpl引用替换为现在新创建的。下一次DelegatingMethodAccessorImpl就不会再交给NativeMethodAccessorImpl执行了,而是交给新生成的java字节码的MethodAccessor。
MethodAccessorGenerator使用了asm字节码动态加载技术,暂不深入研究只
总结,一个方法可以生成多个方法对象,但只有一个根对象,主要用于持有一个MethodAccessor对象,这个对象也可以认为一个方法只有一个,相当于是静态的。因为方法的调用是交给MethodAccessor执行的,所以我所想要知道的答案在MethodAccessor的调用中,深入MethodAccessor:,
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - MethodAccessor - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
假如有这么一个类,,
公共类{ 公共空间foo(字符串名称){ system . out。println(“你好,”+名字); } }
可以编写另外一个类来反射调用一个上的方法:,
进口java.lang.reflect.Method; 公开课TestClassLoad { 公共静态void main (String [] args){抛出异常 Class<& # 63;比;clz=forname (“A”); 对象o=clz.newInstance (); m=clz方法。getMethod (" foo ", String.class); for (int i=0;我& lt;16;我+ +){ m。调用(o, Integer.toString (i)); } } }
注意到TestClassLoad类上不会有对类一个的符号依赖,也就是说在加载并初始化TestClassLoad类时不需要关心类一个的存在与否,而是等到主要()方法执行到调用forName()时才试图对类一个做动态加载;这里用的是一个参数版的forName(),也就是使用当前方法所在类的类加载器来加载,并且初始化新加载的类。……好吧这个细节跟主题没啥关系只
回到主题。这次我的测试环境是Sun的JDK 1.6.0更新13构建03。编译上述代码,并在执行TestClassLoad时加入- xx: + TraceClassLoading参数(或者- verbose: class或者直接- verbose都行),如下:
java - xx: + TraTestClassLoad, ceClassLoading