这篇博客主要是来分析下Java反射机制实现的核心类Class
public class Test {
public static void main(String[] args) {
Class clazz = String.class;
Constructor[] constructors = clazz.getConstructors();
}
}
JVM通过ClassLoader把类的class字节码文件加载到方法区内存当中,以上是通过一个Class对象获取到某个具体类当中的构造方法,我们来看下实现方式准备工作,先看下Class当中经常用到的内部类,和属性
private static boolean useCaches = true; //是否使用RedefineClasses作为缓存数据
// reflection data that might get invalidated when JVM TI RedefineClasses() is called
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;
}
}
// 保存一个软引用的对象
private volatile transient SoftReference<ReflectionData<T>> reflectionData;
// Incremented by the VM on each call to JVM TI RedefineClasses()
// 用来判断和ReflectionData当中redefinedCount的值是否相同,如果不同说明缓存当中的数据失效
private volatile transient int classRedefinedCount = 0;
@CallerSensitive
public Constructor<?>[] getConstructors() throws SecurityException {
checkMemberAccess(Member.PUBLIC, Reflection.getCallerClass(), true); //判断是否有访问权限
return copyConstructors(privateGetDeclaredConstructors(true)); //获取到声明的构造方法,并拷贝一份构造方法
}
接下来我们来看下获取构造方法的实现privateGetDeclaredConstructors(true)
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>[]) new Constructor<?>[0];
res = temporaryRes;
} else {
res = getDeclaredConstructors0(publicOnly);
}
if (rd != null) {
if (publicOnly) {
rd.publicConstructors = res;
} else {
rd.declaredConstructors = res;
}
}
return res;
}
- checkInitted() 来判断是否配置了useCached属性,通过sun.reflect.noCaches来配置,如果配置的话,将useCached改为配置的属性
- reflectionData()获取缓存当中的数据,如果缓存当中有数据,直接返回缓存当中的构造方法
- 如果缓存当中没有数据,就从JVM当中读取数据
- 如果是接口类型,直接生成一个数组长度为0的Constructor数组,因为接口没有构造方法
- 如果不是接口类型,从JVM当中获取getDeclaredConstructors0 是native方法
- 最后更新缓存reflectionData当中的构造方法
接下来,我们来看下reflectionData()方法,如何获取缓存数据,主要是延迟创建,并缓存数据
private ReflectionData<T> reflectionData() {
SoftReference<ReflectionData<T>> reflectionData = this.reflectionData;
int classRedefinedCount = this.classRedefinedCount;
ReflectionData<T> rd;
if (useCaches &&
reflectionData != null &&
(rd = reflectionData.get()) != null &&
rd.redefinedCount == classRedefinedCount) {
return rd;
}
// else no SoftReference or cleared SoftReference or stale ReflectionData
// -> create and replace new instance
return newReflectionData(reflectionData, classRedefinedCount);
}
- 首先获取当前reflectionData
- 如果可以使用缓存,并且缓存当中的数据不为null,而且缓存没有失效,(缓存当中redefinedCount等于classRedefinedCount的值),直接返回缓存当中的reflectionData
- 如果以上都不是的话,就创建新的reflectionData,并保存到缓存当中去
我们来看下newReflectionData方法的实现
private ReflectionData<T> newReflectionData(SoftReference<ReflectionData<T>> oldReflectionData,
int classRedefinedCount) {
if (!useCaches) return null;
while (true) {
ReflectionData<T> rd = new ReflectionData<>(classRedefinedCount);
// try to CAS it...
if (Atomic.casReflectionData(this, oldReflectionData, new SoftReference<>(rd))) {
return rd;
}
// else retry
oldReflectionData = this.reflectionData;
classRedefinedCount = this.classRedefinedCount;
if (oldReflectionData != null &&
(rd = oldReflectionData.get()) != null &&
rd.redefinedCount == classRedefinedCount) {
return rd;
}
}
}
- 首先,还是判断是否使用缓存,如果不使用,直接返回
- 使用while+CAS方式更新数据,创建一个新的ReflectionData,如果更新成功直接返回,否则进入3
- 获取到旧的reflectionData和classRedefinedCount的值,如果旧的值不为null, 并且缓存未失效,说明其他线程更新成功了,直接返回
Constructor.newInstance()实现
在上面获取到Constructor之后,通过newInstance的方式获取到实例方法
public T newInstance(Object ... initargs)
throws InstantiationException, IllegalAccessException,
IllegalArgumentException, InvocationTargetException
{
if (!override) {
if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) {
Class<?> caller = Reflection.getCallerClass();
checkAccess(caller, clazz, null, modifiers);
}
}
if ((clazz.getModifiers() & Modifier.ENUM) != 0)
throw new IllegalArgumentException("Cannot reflectively create enum objects");
ConstructorAccessor ca = constructorAccessor; // read volatile
if (ca == null) {
ca = acquireConstructorAccessor();
}
@SuppressWarnings("unchecked")
T inst = (T) ca.newInstance(initargs);
return inst;
}
- 判断语言级别的访问权限是否被覆盖,如果没有被覆盖需要检查是否有访问权限
- 判断是否为枚举类型,如果是枚举类型不能通过反射创建
- 获取constructorAccessor,如果为null, 通过acquireConstructorAccessor获取
- 通过ConstructorAccessor创建实例对象
接下来来看下如果构建ConstructorAccessor
private ConstructorAccessor acquireConstructorAccessor() {
// First check to see if one has been created yet, and take it
// if so.
ConstructorAccessor tmp = null;
if (root != null) tmp = root.getConstructorAccessor();
if (tmp != null) {
constructorAccessor = tmp;
} else {
// Otherwise fabricate one and propagate it up to the root
tmp = reflectionFactory.newConstructorAccessor(this);
setConstructorAccessor(tmp);
}
return tmp;
}
- 先判断是否已经创建了ConstructorAccessor,如果已经创建了,直接返回获取就可以
- 通过reflectionFactory来创建一个新的ConstructorAccessor
- 设置当前Class对象当中的ConstructorAccessor对象
接下来通过RelectionFactory来创建ConstructorAccessor方法的实现
public ConstructorAccessor newConstructorAccessor(Constructor<?> var1) {
checkInitted();
Class var2 = var1.getDeclaringClass();
if(Modifier.isAbstract(var2.getModifiers())) {
return new InstantiationExceptionConstructorAccessorImpl((String)null);
} else if(var2 == Class.class) {
return new InstantiationExceptionConstructorAccessorImpl("Can not instantiate java.lang.Class");
} else if(Reflection.isSubclassOf(var2, ConstructorAccessorImpl.class)) {
return new BootstrapConstructorAccessorImpl(var1);
} else if(noInflation && !ReflectUtil.isVMAnonymousClass(var1.getDeclaringClass())) {
return (new MethodAccessorGenerator()).generateConstructor(var1.getDeclaringClass(), var1.getParameterTypes(), var1.getExceptionTypes(), var1.getModifiers());
} else {
NativeConstructorAccessorImpl var3 = new NativeConstructorAccessorImpl(var1);
DelegatingConstructorAccessorImpl var4 = new DelegatingConstructorAccessorImpl(var3);
var3.setParent(var4);
return var4;
}
}
- checkInitted来判断一些配置参数是否设置
- 如果是抽象类的构造方法,会创建一个InstantiationExeceptionConstructorAccessorImpl,也是个ConstructorAccessor的一个实现,不过他的newInstance会直接抛出异常
- 如果当前构造方法等于Class对象直接抛出异常
- 如果当前类是ConstructorAccessorImpl的一个子类,构建一个BootstrapConstructorAccessorImpl的类
- 判断是否启用inflation如果启用了,并且当前类不是匿名内部类,使用MethodAccessorGenerator来生成ConstructorAccessor
- 否则就通过NativeConstructorAccessorImpl的方式来构建,当然如果构建次数超过了inflationThreshold(15)就是用MethodAccessorGenerator方式来构建。
接下来我们看下关于Method的构建和调用
首先我们来看获取指定的Method对象方法
public Method getDeclaredMethod(String name, Class<?>... parameterTypes)
throws NoSuchMethodException, SecurityException {
checkMemberAccess(Member.DECLARED, Reflection.getCallerClass(), true);
Method method = searchMethods(privateGetDeclaredMethods(false), name, parameterTypes);
if (method == null) {
throw new NoSuchMethodException(getName() + "." + name + argumentTypesToString(parameterTypes));
}
return method;
}
- 判断当前method是否有访问权限
- privateGetDeclaredMethods获取到当前所声明的所有方法
- 根据当前传递的方法名和参数类型从声明的方法中找到匹配的方法,并返回
接下来我们先来看privateGetDeclaredMethods方法的实现
private Method[] privateGetDeclaredMethods(boolean publicOnly) {
checkInitted();
Method[] res;
ReflectionData<T> rd = reflectionData();
if (rd != null) {
res = publicOnly ? rd.declaredPublicMethods : rd.declaredMethods;
if (res != null) return res;
}
// No cached value available; request value from VM
res = Reflection.filterMethods(this, getDeclaredMethods0(publicOnly));
if (rd != null) {
if (publicOnly) {
rd.declaredPublicMethods = res;
} else {
rd.declaredMethods = res;
}
}
return res;
}
- 同样的判断当前是否有配置信息,读取是否从缓存中获取数据
- 如果缓存当中有数据直接拿缓存当中的数据返回
- 如果没有缓存数据,从JVM当中读取数据,getDeclaredMethods0(publicOnly) 使用native方式读取methods数组对象
- 将缓存当中的数据更新
接下来来看下关于Method的invoke方法,总体上和构造方法的newInstance很类似
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);
}
主要是创建MethodAccessor方法,首先要获取到MethodAccessor,基于上面对构造方法的分析我们直接到创建MethodAccessor的方法中去看
public MethodAccessor newMethodAccessor(Method var1) {
checkInitted();
if(noInflation && !ReflectUtil.isVMAnonymousClass(var1.getDeclaringClass())) {
return (new MethodAccessorGenerator()).generateMethod(var1.getDeclaringClass(), var1.getName(), var1.getParameterTypes(), var1.getReturnType(), var1.getExceptionTypes(), var1.getModifiers());
} else {
NativeMethodAccessorImpl var2 = new NativeMethodAccessorImpl(var1);
DelegatingMethodAccessorImpl var3 = new DelegatingMethodAccessorImpl(var2);
var2.setParent(var3);
return var3;
}
}
默认情况下我们设置的noInflation=false,所以我们主要看通过创建的DelegationMehtodAccessorImpl,我们来看下它的实现方法
class DelegatingMethodAccessorImpl extends MethodAccessorImpl {
private MethodAccessorImpl delegate;
DelegatingMethodAccessorImpl(MethodAccessorImpl var1) {
this.setDelegate(var1);
}
public Object invoke(Object var1, Object[] var2) throws IllegalArgumentException, InvocationTargetException {
return this.delegate.invoke(var1, var2);
}
void setDelegate(MethodAccessorImpl var1) {
this.delegate = var1;
}
}
可以看到这个类的实现是通过里面的代理对象delegate来实现的,从上面方法我们可以看到,代理对象是NativeMethodAccessorImpl
public Object invoke(Object var1, Object[] var2) throws IllegalArgumentException, InvocationTargetException {
if(++this.numInvocations > ReflectionFactory.inflationThreshold() && !ReflectUtil.isVMAnonymousClass(this.method.getDeclaringClass())) {
MethodAccessorImpl var3 = (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(var3);
}
return invoke0(this.method, var1, var2);
}
这里可以看到会判断numInvocations的次数和inflationThreshold的大小,inflationThreshod默认是15,可以通过配置文件修改,如果调用次数超过了设定值,那么久还是通过MethodAccessorGenerator的方式来创建MethodAccessorImpl
这里需要注意下,通过MethodAccessorGenerator的方式生成,速度要比Native的快,但是第一次执行非常耗时,而Native方式执行比较耗时,但是第一次执行并不耗时,所以配置inflation和inflationThreshold是为了在启动时间和执行时间上面做一个考量。
通过sun.reflect.noInflation和sun.reflect.inflationThreshold来进行配置。
关于面试
以下三种获取Class对象的方式有什么不同?
1、new Object().getClass 2、Object.class 3、 Class.forName("java.util.String")
我们给出一个代码实例
public class Test {
static {
System.out.println("静态代码块");
}
{
System.out.println("动态代码块");
}
public Test(){
System.out.println("构造方法");
}
public static void main(String[] args) {
Class<?> clazz1 = Test.class;
System.out.println("-----------");
try{
Class<?> clazz2 = Class.forName("com.reflect.Test");
}catch (ClassNotFoundException e){
e.printStackTrace();
}
System.out.println("-----------");
Class<?> clazz3 = new Test().getClass();
}
}
看下打印结果
静态代码块
-----------
-----------
动态代码块
构造方法
分别来分析以下,通过Test.class的方式只执行了静态代码块,通过Class.forName形式的话,也只执行静态代码块,而通过构造方法去执行,如果已经执行过静态代码块将不会执行静态代码块,如果没有执行过静态代码块,需要执行静态代码块,动态代码块,及构造方法
静态代码块只执行一次,因此在测试每个构造Class的方法时,建议不要像上面那样去执行,最好是分别执行测试,这一点我发现好多博客对Object.class和Class.forName方式的分析和执行结果其实是错误的,两者都是只执行静态代码块。