深入理解java反射
2018-06-13 17:35
23 查看
一个反射的简单例子:(给出关键代码)
Class c = Class.forName("demo.MyClass"); Object aim = c.newInstance(); Method method = c.getMethod("myMethod"); method.invoke(aim);
第一行代码加载得到了目标类的Class对象,还可以通过其他方式得到,如:调用对象的getClass() 等,第二行代码得到Class类的一个对象(目标调动对象),第三行从Class 对象中得到了Method 对象,第四行传入目标对象通过反射调用目标对象的方法。
接下来重点看看第三四行代码是如何实现的:
Method method = c.getMethod("say");
Class对象是在加载类时由JVM构造的,JVM为每个类管理一个独一无二的Class对象,这份Class对象里维护着该类的所有Method,Field,Constructor的cache,这份cache也可以被称作根对象。每次getMethod获取到的Method对象都持有对根对象的引用,因为一些重量级的Method的成员变量(主要是MethodAccessor),我们不希望每次创建Method对象都要重新初始化,于是所有代表同一个方法的Method对象都共享着根对象的MethodAccessor,每一次创建都会调用根对象的copy方法复制一份:
Method copy() { Method res = new Method(clazz, name, parameterTypes, returnType, exceptionTypes, modifiers, slot, signature, annotations, parameterAnnotations, annotationDefault); res.root = this; res.methodAccessor = methodAccessor; return res; }
知道了getMethod()的原理后,接着看第四行:
method.invoke(aim)
查看invoke源码
public Object invoke(Object obj, Object... args) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException { if (!override) { if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) { Class<?> caller = Reflection.getCallerClass(); checkAccess(caller, clazz, obj, modifiers); } } MethodAccessor ma = methodAccessor; // read volatile if (ma == null) { ma = acquireMethodAccessor(); } return ma.invoke(obj, args); }
可以看到,调用Method.invoke之后,会直接去调MethodAccessor.invoke(),MethodAccessor就是上面提到的所有同名method共享的一个实例,由ReflectionFactory创建
reflectionFactory.newMethodAccessor(this);创建机制采用了一种名为
inflation的方式(JDK1.4之后):
如果该方法的累计调用次数<=15,会创建出
NativeMethodAccessorImpl它的实现就是直接调用native方法实现反射;如果该方法的累计调用次数>15,会由java代码创建出字节码组装而成的MethodAccessorImpl。(是否采用inflation和15这个数字都可以在jvm参数中调整)
以调用MyClass.myMethod(String s)为例,生成出的MethodAccessorImpl字节码翻译成Java代码大致如下:
public class GeneratedMethodAccessor1 extends MethodAccessorImpl { public Object invoke(Object obj, Object[] args) throws Exception { try { MyClass target = (MyClass) obj; String arg0 = (String) args[0]; target.myMethod(arg0); } catch (Throwable t) { throw new InvocationTargetException(t); } } }
至于native方法的实现,由于比较深入本文就不探讨了
相关文章推荐
- 深入理解Java反射
- Java范型深入理解,利用反射穿透编译器忽略范型
- 深入理解 Java 反射:Class (反射的入口)
- 深入理解 Java 反射:Method (成员方法)
- 深入理解Java:类加载机制及反射
- Java范型深入理解,利用反射穿透编译器忽略范型
- 深入理解Java:类加载机制及反射
- 深入理解Java:类加载机制及反射
- 深入理解Java:类加载机制及反射
- 深入理解 Java 反射:Class (反射的入口)
- 深入理解java---反射篇
- 深入理解Java:类加载机制及反射
- 深入理解Java反射
- 深入理解Java:类加载机制及反射
- 深入理解Java的内省与反射
- 深入理解Java:类加载机制及反射
- 深入理解Java类型信息(Class对象)与反射机制
- 深入理解Java:类加载机制及反射
- 深入理解Java之反射
- 深入理解Java:类加载机制及反射