在《Java反射机制(一)—— 使用反射》一文中我们提到,在类的初始化阶段会创建对应类的一个Class对象,Class对象里还缓存了该类的所有Constructor对象、Method对象、Filed对象。这个初始化阶段是在JDK底层以C语言实现的,有兴趣可以自行查看。本文只对反射机制是如何使用Class对象实现实例创建、方法调用、属性访问进行说明。
1.反射创建对象的过程
1.1反射获取Constructor对象的过程
反射创建一个类的对象是从获取该类的Constructor(构造器)对象开始的。Class对象获取特定构造函数对象的方法是getDeclaredConstructor(Class<?>… parameterTypes) 。
JDK源码
/*Class*/
@CallerSensitive
public Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes)
throws NoSuchMethodException, SecurityException {
checkMemberAccess(Member.DECLARED, Reflection.getCallerClass(), true);
return getConstructor0(parameterTypes, Member.DECLARED);
}
private Constructor<T> getConstructor0(Class<?>[] parameterTypes,
int which) throws NoSuchMethodException
{
Constructor<T>[] constructors = privateGetDeclaredConstructors((which == Member.PUBLIC));
for (Constructor<T> constructor : constructors) {
if (arrayContentsEq(parameterTypes,
constructor.getParameterTypes())) {
return getReflectionFactory().copyConstructor(constructor);
}
}
throw new NoSuchMethodException(getName() + ".<init>" + argumentTypesToString(parameterTypes));
}
从上面两个方法不难看出,要获取目标Constructor对象分为两步,获取Class对象的所有构造器对象,根据参数类型数组获取到特定的构造器对象。
获取所有构造器对象的方法是privateGetDeclaredConstructors,在该方法中,会先试图获取Class对象在类初始化阶段就缓存的该类的所有Constructor对象,那这个缓存在什么位置呢,这个缓存就是Class的属性private volatile transient SoftReference<ReflectionData> reflectionData。这个属性的类型是SoftReference(软引用),所谓软引用就是在资源紧张的情况下GC会进行回收,这就可能导致缓存丢失。SoftReference的泛型是ReflectionData,ReflectionData就是缓存数据的真正格式。我们来看一下ReflectionData是怎么缓存数据的。
JDK源码
/*Class$ReflectionData*/
private static class ReflectionData<T> {
volatile Field[] declaredFields;
volatile Field[] publicFields;
volatile Method[] declaredMethods;
volatile Method[] publicMethods;
volatile Constructor<T>[] declaredConstructors;
volatile Constructor<T>[] publicConstructors;
// Intermediate results for getFields and getMethods
volatile Field[] declaredPublicFields;
volatile Method[] declaredPublicMethods;
volatile Class<?>[] interfaces;
// Value of classRedefinedCount when we created this ReflectionData instance
final int redefinedCount;
ReflectionData(int redefinedCount) {
this.redefinedCount = redefinedCount;
}
}
ReflectionData用数据的形式,将所有的Constructor、Method、Field对象存储下来供反射进行使用。
在新版本的JDK中对该缓存进行了优化,放弃使用ReflectionData存储,而是在Class中直接将Constructor、Method、Field数组放进软引用中作为缓存。这样就将缓存分散,当资源紧张时,不会一次全部被GC回收
了解了Class对象如何缓存Constructor,下面我们就来看privateGetDeclaredConstructors方法的源码。
JDK源码
private Constructor<T>[] privateGetDeclaredConstructors(boolean publicOnly) {
checkInitted();
Constructor<T>[] res;
ReflectionData<T> rd = reflectionData();
if (rd != null) {
res = publicOnly ? rd.publicConstructors : rd.declaredConstructors;
if (res != null) return res;
}
// No cached value available; request value from VM
if (isInterface()) {
@SuppressWarnings("unchecked")
Constructor<T>[] temporaryRes = (Constructor<T