反射的概念
- 反射:Refelection,反射是Java的特征之一,允许运行中的Java程序获取自身信息,并可以操作类或者对象的内部属性
- 通过反射,可以在运行时获得程序或者程序中的每一个类型的成员活成成员的信息
- 程序中的对象一般都是在编译时就确定下来,Java反射机制可以动态地创建对象并且调用相关属性,这些对象的类型在编译时是未知的
- 也就是说 ,可以通过反射机制直接创建对象,即使这个对象类型在编译时是未知的
- Java反射提供下列功能:
- 在运行时判断任意一个对象所属的类
- 在运行时构造任意一个类的对象
- 在运行时判断任意一个类所具有的成员变量和方法,可以通过反射调用 private 方法
- 在运行时调用任意一个对象的方法
反射调用方法原理
- 首先Java通过字节码获取类的基本信息,其次通过Class#getMethod(“myMethod”)经过查找获取Method对象
- 接着通过Method#invoke调用方法, 此处包括Native版本和Java版本实现
- Native版本的invoke0()在HotSpot VM里是由JVM_InvokeMethod()支持
- JVM_InvokeMethod()中通过JNIHandles::resolve(method)解析方法的符号引用(个人理解, 详情参考R大博客)
- 拿到method_handle后, 即符号引用, 获取方法的返回类型等相关信息, 最后调用invoke()执行方法
- 含native版本以及Java版本, native版本初始化快, 但由于对JVM是黑盒, 因此无法内联等优化, 当超过15次时, 会自动转成Java版本, Java版本初始化慢, 但长时间执行效率更高, 可进行内联等优化
public final
class Method extends AccessibleObject implements GenericDeclaration, Member {
public Object invoke(Object obj, Object... args)
throws IllegalAccessException, IllegalArgumentException,
InvocationTargetException
{
...
return methodAccessor.invoke(obj, args);
}
}
public class ReflectionFactory {
public MethodAccessor newMethodAccessor(Method method) {
...
if (noInflation) {
return new MethodAccessorGenerator().
generateMethod(method.getDeclaringClass(),
method.getName(),
method.getParameterTypes(),
method.getReturnType(),
method.getExceptionTypes(),
method.getModifiers());
} else {
NativeMethodAccessorImpl acc =
new NativeMethodAccessorImpl(method);
DelegatingMethodAccessorImpl res =
new DelegatingMethodAccessorImpl(acc);
acc.setParent(res);
return res;
}
}
}
class NativeMethodAccessorImpl extends MethodAccessorImpl {
...
public Object invoke(Object obj, Object[] args)
throws IllegalArgumentException, InvocationTargetException
{
if (++numInvocations > ReflectionFactory.inflationThreshold()) {
MethodAccessorImpl acc = (MethodAccessorImpl)
new MethodAccessorGenerator().
generateMethod(method.getDeclaringClass(),
method.getName(),
method.getParameterTypes(),
method.getReturnType(),
method.getExceptionTypes(),
method.getModifiers());
parent.setDelegate(acc);
}
return invoke0(method, obj, args);
}
...
private static native Object invoke0(Method m, Object obj, Object[] args);
}
public class GeneratedMethodAccessor1 extends MethodAccessorImpl {
...
public Object invoke(Object obj, Object[] args)
throws IllegalArgumentException, InvocationTargetException {
...
try {
target.foo(arg0);