反射机制是Java的亮点之一,基于反射可动态调用某对象实例中对应的方法、访问查看对象的属性等**
而无需在编写代码时就确定需要创建的对象,这使得Java可以实现很灵活的实现对象的调用,代码示例如:
Class actionClass=Class.forName(外部实现类);
Method method=actionClass.getMethod(“execute”,null);
Object action=actionClass.newInstance();
method.invoke(action,null);
反射的关键:要实现动态的调用,最明显的方法就是动态的生成字节码,加载到JVM中并执行。
(1)Class actionClass=Class.forName(外部实现类);
调用本地方法,使用调用者所在的ClassLoader来加载创建出Class对象;
(2)Method method=actionClass.getMethod(“execute”,null);
校验此Class是否为public类型的,以确定类的执行权限,如不是public类型的,则直接抛出SecurityException;调用privateGetDeclaredMethods来获取到此Class中所有的方法,在privateGetDeclaredMethods对此Class中所有的方法的集合做了缓存,在第一次时会调用本地方法去获取;
扫描方法集合列表中是否有相同方法名以及参数类型的方法,如有则复制生成一个新的Method对象返回;
如没有则继续扫描父类、父接口中是否有此方法,如仍然没找到方法则抛出NoSuchMethodException;
(3) Object action=actionClass.newInstance();
第一步:校验此Class是否为public类型,如权限不足则直接抛出SecurityException;
第二步:如没有缓存的构造器对象,则调用本地方法获取到构造器,并复制生成一个新的构造器对象,放入缓存,如没有空构造器则抛出InstantiationException;
第三步:校验构造器对象的权限;
第四步:执行构造器对象的newInstance方法;构造器对象的newInstance方法判断是否有缓存的ConstructorAccessor对象,如果没有则调用sun.reflect.ReflectionFactory生成新的ConstructorAccessor对象;
第五步:sun.reflect.ReflectionFactory判断是否需要调用本地代码,可通过sun.reflect.noInflation=true来设置为不调用本地代码,在不调用本地代码的情况下,就转交给MethodAccessorGenerator来处理了;
第六步:MethodAccessorGenerator中的generate方法根据Java Class格式规范生成字节码,字节码中包括了ConstructorAccessor对象需要的newInstance方法,此newInstance方法对应的指令为invokespecial,所需的参数则从外部压入,生成的Constructor类的名字以:sun/reflect/GeneratedSerializationConstructorAccessor或sun/reflect/GeneratedConstructorAccessor开头,后面跟随一个累计创建的对象的次数;
第七步:在生成了字节码后将其加载到当前的ClassLoader中,并实例化,完成ConstructorAccessor对象的创建过程,并将此对象放入构造器对象的缓存中;
最后一步:执行获取的constructorAccessor.newInstance,这步和标准的方法调用没有任何区别。
(4) method.invoke(action,null);
这步执行的过程和上一步基本类似,只是在生成字节码时生成的方法改为了invoke,其调用的目标改为了传入的对象的方法,同时生成的类名改为了:sun/reflect/GeneratedMethodAccessor。