本文共 13728 字,大约阅读时间需要 45 分钟。
这篇博客主要是来分析下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{ volatile Field[] declaredFields; volatile Field[] publicFields; volatile Method[] declaredMethods; volatile Method[] publicMethods; volatile Constructor [] declaredConstructors; volatile Constructor [] 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; // 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[] privateGetDeclaredConstructors(boolean publicOnly) { checkInitted(); Constructor [] res; ReflectionData 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 [] temporaryRes = (Constructor []) new Constructor [0]; res = temporaryRes; } else { res = getDeclaredConstructors0(publicOnly); } if (rd != null) { if (publicOnly) { rd.publicConstructors = res; } else { rd.declaredConstructors = res; } } return res; }
1、checkInitted() 来判断是否配置了useCached属性,通过sun.reflect.noCaches来配置,如果配置的话,将useCached改为配置的属性
2、reflectionData()获取缓存当中的数据,如果缓存当中有数据,直接返回缓存当中的构造方法
3、如果缓存当中没有数据,就从JVM当中读取数据
4、如果是接口类型,直接生成一个数组长度为0的Constructor数组,因为接口没有构造方法
5、如果不是接口类型,从JVM当中获取getDeclaredConstructors0 是native方法
6、最后更新缓存reflectionData当中的构造方法
接下来,我们来看下reflectionData()方法,如何获取缓存数据,主要是延迟创建,并缓存数据
private ReflectionDatareflectionData() { SoftReference > reflectionData = this.reflectionData; int classRedefinedCount = this.classRedefinedCount; ReflectionData 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); }
1、首先获取当前reflectionData
2、如果可以使用缓存,并且缓存当中的数据不为null,而且缓存没有失效,(缓存当中redefinedCount等于classRedefinedCount的值),直接返回缓存当中的reflectionData
3、如果以上都不是的话,就创建新的reflectionData,并保存到缓存当中去
我们来看下newReflectionData方法的实现
private ReflectionDatanewReflectionData(SoftReference > oldReflectionData, int classRedefinedCount) { if (!useCaches) return null; while (true) { ReflectionData 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; } } }
1、首先,还是判断是否使用缓存,如果不使用,直接返回
2、使用while+CAS方式更新数据,创建一个新的ReflectionData,如果更新成功直接返回,否则进入3
3、获取到旧的reflectionData和classRedefinedCount的值,如果旧的值不为null, 并且缓存未失效,说明其他线程更新成功了,直接返回
在上面获取到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; }
1、判断语言级别的访问权限是否被覆盖,如果没有被覆盖需要检查是否有访问权限
2、判断是否为枚举类型,如果是枚举类型不能通过反射创建
3、获取constructorAccessor,如果为null, 通过acquireConstructorAccessor获取
4、通过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; }
1、先判断是否已经创建了ConstructorAccessor,如果已经创建了,直接返回获取就可以
2、通过reflectionFactory来创建一个新的ConstructorAccessor
3、设置当前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; } }
1、checkInitted来判断一些配置参数是否设置
2、如果是抽象类的构造方法,会创建一个InstantiationExeceptionConstructorAccessorImpl,也是个ConstructorAccessor的一个实现,不过他的newInstance会直接抛出异常
3、如果当前构造方法等于Class对象直接抛出异常
4、如果当前类是ConstructorAccessorImpl的一个子类,构建一个BootstrapConstructorAccessorImpl的类
5、判断是否启用inflation如果启用了,并且当前类不是匿名内部类,使用MethodAccessorGenerator来生成ConstructorAccessor
6、否则就通过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; }
1、判断当前method是否有访问权限
2、privateGetDeclaredMethods获取到当前所声明的所有方法
3、根据当前传递的方法名和参数类型从生命的方法中找到匹配的方法,并返回
接下来我们先来看privateGetDeclaredMethods方法的实现
private Method[] privateGetDeclaredMethods(boolean publicOnly) { checkInitted(); Method[] res; ReflectionDatard = 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; }
1、同样的判断当前是否有配置信息,读取是否从缓存中获取数据
2、如果缓存当中有数据直接拿缓存当中的数据返回
3、如果没有缓存数据,从JVM当中读取数据,getDeclaredMethods0(publicOnly) 使用native方式读取methods数组对象
4、将缓存当中的数据更新
接下来来看下关于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方式的分析和执行结果其实是错误的,两者都是只执行静态代码块。
转载地址:http://tlvti.baihongyu.com/