1 反射的概述
程序在运行状态中,对于任意一个类,都可以知道这个类的所有属性和方法;对于任意一个对象,都能够调用他的任意方法和属性。这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。
java文件都会被编译成一个.class文件,类被加载以后,class文件会被加载到虚拟机中Java虚拟机,在内存中自动产生一个Class对象。Class对象承载了这个类的所有信息,包括父类、接口、构造函数、方法、属性等。
2 获取class对象的方法
获取class对象主要有以下三种方式,下面以Person为例说明。注意,一个类在 JVM 中只会有一个 Class 实例。
Class.forName("全类名")
Class c = Class.forName("com.reflex.Person");
- 类名.class
Class c = Person.class;
- 对象.getClass()
Person p = new Person();
Class c = p.getClass();
3 反射的作用
利用反射可以程序运行时动态访问和修改任何类的行为和状态。反射最重要的用途就是开发各种通用框架.
3.1 动态创建对象
通过反射创建类对象主要有两种方式:
- 通过 Class 对象的 newInstance() 方法
Class<?> c = String.class;
Object str = c.newInstance();
- 通过 Constructor 对象的 newInstance() 方法
/* 获取String所对应的Class对象 */
Class<?> c = String.class;
/* 获取String类带一个String参数的构造器 */
Constructor constructor =c.getConstructor(String.class);
/* 根据构造器创建实例 */
Object obj=constructor.newInstance("abc");
3.2 动态操作属性
- getFileds: 获取公有的成员变量
- getDeclaredFields: 获取所有已声明的成员变量,但是不能得到父类的成员变量
3.3 动态调用方法
- getMethods(): 返回某个类所有的public方法
public Method[] getMethods() throws SecurityException {}
- getMethod(): 返回一个特定的方法
// name :方法名称
// parameterType :方法的参数对应Class的对象
public Method getMethod(String name,Class<?>... parameterType) {}
- getDeclaredMethods(): 返回类或接口声明的所有方法
//包括公共,保护,默认(包)访问和私有方法
//不包括继承的方法
public Method[] getDeclaredMethods() throws SecurityException {}
从类中获取一个方法后,可以使用invoke() 来调用这个方法
public Object invoke(Object obj, Object ... args) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException {}
4 Method.invoke()的原理
JDK里Method.invoke()实际上并不是自己实现的反射调用逻辑,而是委托给sun.reflect.MethodAccessor来处理。
public final class Method extends Executable {
private volatile MethodAccessor methodAccessor;
public Object invoke(Object obj, Object... args) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException {
if (!this.override) {
Class<?> caller = Reflection.getCallerClass();
this.checkAccess(caller, this.clazz, Modifier.isStatic(this.modifiers) ? null : obj.getClass(), this.modifiers);
}
MethodAccessor ma = this.methodAccessor;
if (ma == null) {
//获取MethodAccessor
ma = this.acquireMethodAccessor();
}
return ma.invoke(obj, args);
}
4.1 Method#root属性
Method中有一个很重要的成员属性root, root对象只有一个,可以理解为root包装了MethodAccessors。在每次通过 getMethod 获取 method 对象时,都会把 root 复制一份返回给用户。同时,会把复制出的对象与 root 建立关联。该 root 对象就是为了共享 MethodAccessors 对象。
public final class Method extends Executable {
// root对象只有一个, root 对象是为了共享 MethodAccessors 对象
private volatile MethodAccessor methodAccessor;
private Method root;
public Object invoke(Object obj, Object... args) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException {
if (!this.override) {
Class<?> caller = Reflection.getCallerClass();
this.checkAccess(caller, this.clazz, Modifier.isStatic(this.modifiers) ? null : obj.getClass(), this.modifiers);
}
MethodAccessor ma = this.methodAccessor;
if (ma == null) {
//获取MethodAccessor
ma = this.acquireMethodAccessor();
}
return ma.invoke(obj, args);
}
private MethodAccessor acquireMethodAccessor() {
// First check to see if one has been created yet, and take it
// if so
MethodAccessor tmp = null;
if (root != null) tmp = root.getMethodAccessor();
if (tmp != null) {
methodAccessor = tmp;
} else {
// Otherwise fabricate one and propagate it up to the root
tmp = reflectionFactory.newMethodAccessor(this);
//把新创建methodAccessor对象通过root包装起来
setMethodAccessor(tmp);
}
return tmp;
}
void setMethodAccessor(MethodAccessor accessor) {
methodAccessor = accessor;
// Propagate up
if (root != null) {
root.setMethodAccessor(accessor);
}
}
}
4.2 MethodAccessor
MethodAccessor 是一个接口,定义了方法调用的具体操作
public interface MethodAccessor {
Object invoke(Object var1, Object[] var2) throws IllegalArgumentException, InvocationTargetException;
}
MethodAccessor实现类
MethodAccessor 有两种实现,一种为使用 bytecodes 实现的 java 版本:
- Native 版本
sun.reflect.NativeMethodAccessorImpl, 一开始启动快,但是随着运行时间边长,速度变慢 - bytecodes 实现的 java 版本,开始加载慢,但是随着运行时间边长,速度变快
sun.reflect.MethodAccessorImpl
DelegatingMethodAccessorImpl
为了完成切换两个版本的切换,引入了DelegatingMethodAccessorImpl
第一次加载的时候使用的是 NativeMethodAccessorImpl 的实现,而当反射调用次数超过 15 次之后,则使用 MethodAccessorGenerator 生成的MethodAccessorImpl 对象去实现反射。
class DelegatingMethodAccessorImpl extends MethodAccessorImpl {
private MethodAccessorImpl delegate;
DelegatingMethodAccessorImpl(MethodAccessorImpl delegate) {
this.setDelegate(delegate);
}
public Object invoke(Object obj, Object[] args) throws IllegalArgumentException, InvocationTargetException {
return this.delegate.invoke(obj, args);
}
void setDelegate(MethodAccessorImpl delegate) {
this.delegate = delegate;
}
}
MethodAccessor的创建
从 acquireMethodAccessor() 方法我们可以看到,
- 代码先判断是否存在对应的 MethodAccessor 对象,如果存在那么就复用之前的 MethodAccessor 对象,否则调用 ReflectionFactory 对象的 newMethodAccessor 方法生成一个 MethodAccessor 对象。
public MethodAccessor newMethodAccessor(Method method) {
checkInitted();
Method root;
if (Reflection.isCallerSensitive(method)) {
root = findMethodForReflection(method);
if (root != null) {
method = root;
}
}
root = (Method)langReflectAccess.getRoot(method);
if (root != null) {
method = root;
}
if (noInflation && !ReflectUtil.isVMAnonymousClass(method.getDeclaringClass())) {
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;
}
}
- DelegatingMethodAccessorImpl使用了代理模式,将 NativeMethodAccessorImpl 对象赋给DelegatingMethodAccessorImpl 的delegate。
而在 NativeMethodAccessorImpl 的 invoke 方法里,其会判断调用次数是否超过阀值(numInvocations)。
class NativeMethodAccessorImpl extends MethodAccessorImpl {
private final Method method;
private DelegatingMethodAccessorImpl parent;
private int numInvocations;
NativeMethodAccessorImpl(Method method) {
this.method = method;
}
public Object invoke(Object obj, Object[] args) throws IllegalArgumentException, InvocationTargetException {
if (++this.numInvocations > ReflectionFactory.inflationThreshold() && !ReflectUtil.isVMAnonymousClass(this.method.getDeclaringClass())) {
MethodAccessorImpl acc = (MethodAccessorImpl)(new MethodAccessorGenerator()).generateMethod(this.method.getDeclaringClass(), this.method.getName(), this.method.getParameterTypes(), this.method.getReturnType(), this.method.getExceptionTypes(), this.method.getModifiers());
this.parent.setDelegate(acc);
}
return invoke0(this.method, obj, args);
}
void setParent(DelegatingMethodAccessorImpl parent) {
this.parent = parent;
}
private static native Object invoke0(Method var0, Object var1, Object[] var2);
}
如果超过该阀值,那么通过MethodAccessorGenerator生成java 版本的 MethodAccessor对象,并将原来 DelegatingMethodAccessorImpl 对象中的 delegate 属性指向最新的java版本的MethodAccessor对象。