深入理解java反射原理
反射是java的一个特性,这一特性也使得它给了广大的第三方框架和开发过者很大的想像空间。
通过反射,java可以动态的加载未知的外部配置对象,临时生成字节码进行加载使用,从而使代码更灵活!可以极大地提高应用的扩展性!
但是,除了停留在使用其华丽功能,我们还可以去看看其实现!
主要看两个方法的使用:
来个例子!
- public class HelloReflect {
- public static void main(String[] args) {
- try {
- // 1. 使用外部配置的实现,进行动态加载类
- TempFunctionTest test = (TempFunctionTest)Class.forName("com.tester.HelloReflect").newInstance();
- test.sayHello("call directly");
- // 2. 根据配置的函数名,进行方法调用(不需要通用的接口抽象)
- Object t2 = new TempFunctionTest();
- Method method = t2.getClass().getDeclaredMethod("sayHello", String.class);
- method.invoke(test, "method invoke");
- } catch (ClassNotFoundException e) {
- e.printStackTrace();
- } catch (InstantiationException e) {
- e.printStackTrace();
- } catch (IllegalAccessException e) {
- e.printStackTrace();
- } catch (NoSuchMethodException e ) {
- e.printStackTrace();
- } catch (InvocationTargetException e) {
- e.printStackTrace();
- }
- }
- public void sayHello(String word) {
- System.out.println("hello," + word);
- }
- }
运行结果显而易见!我们来看执行流程!
1. 反射获取类实例 Class.forName("C.a.xxx");
首先调用了 java.lang.Class 的静态方法,获取类信息!
- @CallerSensitive
- public static Class<?> forName(String className)
- throws ClassNotFoundException {
- // 先通过反射,获取调用进来的类信息,从而获取当前的 classLoader
- Class<?> caller = Reflection.getCallerClass();
- // 调用native方法进行获取class信息
- return forName0(className, true, ClassLoader.getClassLoader(caller), caller);
- }
forName()反射获取类信息,并没有将实现留给了java,而是交给了jvm去加载!
主要是先获取 ClassLoader, 然后调用 native 方法,获取信息,加载类则是回调 java.lang.ClassLoader.
最后,jvm又会回调 ClassLoader 进类加载!
- //
- public Class<?> loadClass(String name) throws ClassNotFoundException {
- return loadClass(name, false);
- }
- // sun.misc.Launcher
- public Class<?> loadClass(String var1, boolean var2) throws ClassNotFoundException {
- int var3 = var1.lastIndexOf(46);
- if(var3 != -1) {
- SecurityManager var4 = System.getSecurityManager();
- if(var4 != null) {
- var4.checkPackageAccess(var1.substring(0, var3));
- }
- }
- if(this.ucp.knownToNotExist(var1)) {
- Class var5 = this.findLoadedClass(var1);
- if(var5 != null) {
- if(var2) {
- this.resolveClass(var5);
- }
- return var5;
- } else {
- throw new ClassNotFoundException(var1);
- }
- } else {
- return super.loadClass(var1, var2);
- }
- }
- // java.lang.ClassLoader
- protected Class<?> loadClass(String name, boolean resolve)
- throws ClassNotFoundException
- {
- // 先获取锁
- synchronized (getClassLoadingLock(name)) {
- // First, check if the class has already been loaded
- // 如果已经加载了的话,就不用再加载了
- Class<?> c = findLoadedClass(name);
- if (c == null) {
- long t0 = System.nanoTime();
- try {
- // 双亲委托加载
- if (parent != null) {
- c = parent.loadClass(name, false);
- } else {
- c = findBootstrapClassOrNull(name);
- }
- } catch (ClassNotFoundException e) {
- // ClassNotFoundException thrown if class not found
- // from the non-null parent class loader
- }
- // 父类没有加载到时,再自己加载
- if (c == null) {
- // If still not found, then invoke findClass in order
- // to find the class.
- long t1 = System.nanoTime();
- c = findClass(name);
- // this is the defining class loader; record the stats
- sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0);
- sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);
- sun.misc.PerfCounter.getFindClasses().increment();
- }
- }
- if (resolve) {
- resolveClass(c);
- }
- return c;
- }
- }
- protected Object getClassLoadingLock(String className) {
- Object lock = this;
- if (parallelLockMap != null) {
- // 使用 ConcurrentHashMap来保存锁
- Object newLock = new Object();
- lock = parallelLockMap.putIfAbsent(className, newLock);
- if (lock == null) {
- lock = newLock;
- }
- }
- return lock;
- }
- protected final Class<?> findLoadedClass(String name) {
- if (!checkName(name))
- return null;
- return findLoadedClass0(name);
- }
下面来看一下 newInstance() 的实现方式!
- // 首先肯定是 Class.newInstance
- @CallerSensitive
- public T newInstance()
- throws InstantiationException, IllegalAccessException
- {
- if (System.getSecurityManager() != null) {
- checkMemberAccess(Member.PUBLIC, Reflection.getCallerClass(), false);
- }
- // NOTE: the following code may not be strictly correct under
- // the current Java memory model.
- // Constructor lookup
- // newInstance() 其实相当于调用类的无参构造函数,所以,首先要找到其无参构造器
- if (cachedConstructor == null) {
- if (this == Class.class) {
- // 不允许调用 Class 的 newInstance() 方法
- throw new IllegalAccessException(
- "Can not call newInstance() on the Class for java.lang.Class"
- );
- }
- try {
- // 获取无参构造器
- Class<?>[] empty = {};
- final Constructor<T> c = getConstructor0(empty, Member.DECLARED);
- // Disable accessibility checks on the constructor
- // since we have to do the security check here anyway
- // (the stack depth is wrong for the Constructor's
- // security check to work)
- java.security.AccessController.doPrivileged(
- new java.security.PrivilegedAction<Void>() {
- public Void run() {
- c.setAccessible(true);
- return null;
- }
- });
- cachedConstructor = c;
- } catch (NoSuchMethodException e) {
- throw (InstantiationException)
- new InstantiationException(getName()).initCause(e);
- }
- }
- Constructor<T> tmpConstructor = cachedConstructor;
- // Security check (same as in java.lang.reflect.Constructor)
- int modifiers = tmpConstructor.getModifiers();
- if (!Reflection.quickCheckMemberAccess(this, modifiers)) {
- Class<?> caller = Reflection.getCallerClass();
- if (newInstanceCallerCache != caller) {
- Reflection.ensureMemberAccess(caller, this, null, modifiers);
- newInstanceCallerCache = caller;
- }
- }
- // Run constructor
- try {
- // 调用无参构造器
- return tmpConstructor.newInstance((Object[])null);
- } catch (InvocationTargetException e) {
- Unsafe.getUnsafe().throwException(e.getTargetException());
- // Not reached
- return null;
- }
- }
newInstance() 主要做了三件事:
1. 权限检测,如果不通过直接抛出异常;
2. 查找无参构造器,并将其缓存起来;
3. 调用具体方法的无参构造方法,生成实例并返回;
下面是获取构造器的过程:
- 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));
- }
getConstructor0() 为获取匹配的构造方器;分三步:
1. 先获取所有的constructors, 然后通过进行参数类型比较;
2. 找到匹配后,通过 ReflectionFactory copy一份constructor返回;
3. 否则抛出 NoSuchMethodException;
- // 获取当前类所有的构造方法,通过jvm或者缓存
- // Returns an array of "root" constructors. These Constructor
- // objects must NOT be propagated to the outside world, but must
- // instead be copied via ReflectionFactory.copyConstructor.
- private Constructor<T>[] privateGetDeclaredConstructors(boolean publicOnly) {
- checkInitted();
- Constructor<T>[] res;
- // 调用 reflectionData(), 获取保存的信息,使用软引用保存,从而使内存不够可以回收
- 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 {
- // 使用native方法从jvm获取构造器
- res = getDeclaredConstructors0(publicOnly);
- }
- if (rd != null) {
- // 最后,将从jvm中读取的内容,存入缓存
- if (publicOnly) {
- rd.publicConstructors = res;
- } else {
- rd.declaredConstructors = res;
- }
- }
- return res;
- }
- // Lazily create and cache 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);
- }
- // 新创建缓存,保存反射信息
- private ReflectionData<T> newReflectionData(SoftReference<ReflectionData<T>> oldReflectionData,
- int classRedefinedCount) {
- if (!useCaches) return null;
- // 使用cas保证更新的线程安全性,所以反射是保证线程安全的
- while (true) {
- ReflectionData<T> rd = new ReflectionData<>(classRedefinedCount);
- // try to CAS it...
- if (Atomic.casReflectionData(this, oldReflectionData, new SoftReference<>(rd))) {
- return rd;
- }
- // 先使用CAS更新,如果更新成功,则立即返回,否则测查当前已被其他线程更新的情况,如果和自己想要更新的状态一致,则也算是成功了
- oldReflectionData = this.reflectionData;
- classRedefinedCount = this.classRedefinedCount;
- if (oldReflectionData != null &&
- (rd = oldReflectionData.get()) != null &&
- rd.redefinedCount == classRedefinedCount) {
- return rd;
- }
- }
- }
如上,privateGetDeclaredConstructors(), 获取所有的构造器主要步骤;
1. 先尝试从缓存中获取;
2. 如果缓存没有,则从jvm中重新获取,并存入缓存,缓存使用软引用进行保存,保证内存可用;
另外,使用 relactionData() 进行缓存保存;ReflectionData 的数据结构如下!
- // 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;
- }
- }
其中,还有一个点,就是如何比较构造是否是要查找构造器,其实就是比较类型完成相等就完了,有一个不相等则返回false。
- private static boolean arrayContentsEq(Object[] a1, Object[] a2) {
- if (a1 == null) {
- return a2 == null || a2.length == 0;
- }
- if (a2 == null) {
- return a1.length == 0;
- }
- if (a1.length != a2.length) {
- return false;
- }
- for (int i = 0; i < a1.length; i++) {
- if (a1[i] != a2[i]) {
- return false;
- }
- }
- return true;
- }
- // sun.reflect.ReflectionFactory
- /** Makes a copy of the passed constructor. The returned
- constructor is a "child" of the passed one; see the comments
- in Constructor.java for details. */
- public <T> Constructor<T> copyConstructor(Constructor<T> arg) {
- return langReflectAccess().copyConstructor(arg);
- }
- // java.lang.reflect.Constructor, copy 其实就是新new一个 Constructor 出来
- Constructor<T> copy() {
- // This routine enables sharing of ConstructorAccessor objects
- // among Constructor objects which refer to the same underlying
- // method in the VM. (All of this contortion is only necessary
- // because of the "accessibility" bit in AccessibleObject,
- // which implicitly requires that new java.lang.reflect
- // objects be fabricated for each reflective call on Class
- // objects.)
- if (this.root != null)
- throw new IllegalArgumentException("Can not copy a non-root Constructor");
- Constructor<T> res = new Constructor<>(clazz,
- parameterTypes,
- exceptionTypes, modifiers, slot,
- signature,
- annotations,
- parameterAnnotations);
- // root 指向当前 constructor
- res.root = this;
- // Might as well eagerly propagate this if already present
- res.constructorAccessor = constructorAccessor;
- return res;
- }
通过上面,获取到 Constructor 了!
接下来就只需调用其相应构造器的 newInstance(),即返回实例了!
- // return tmpConstructor.newInstance((Object[])null);
- // java.lang.reflect.Constructor
- @CallerSensitive
- 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;
- }
- // sun.reflect.DelegatingConstructorAccessorImpl
- public Object newInstance(Object[] args)
- throws InstantiationException,
- IllegalArgumentException,
- InvocationTargetException
- {
- return delegate.newInstance(args);
- }
- // sun.reflect.NativeConstructorAccessorImpl
- public Object newInstance(Object[] args)
- throws InstantiationException,
- IllegalArgumentException,
- InvocationTargetException
- {
- // We can't inflate a constructor belonging to a vm-anonymous class
- // because that kind of class can't be referred to by name, hence can't
- // be found from the generated bytecode.
- if (++numInvocations > ReflectionFactory.inflationThreshold()
- && !ReflectUtil.isVMAnonymousClass(c.getDeclaringClass())) {
- ConstructorAccessorImpl acc = (ConstructorAccessorImpl)
- new MethodAccessorGenerator().
- generateConstructor(c.getDeclaringClass(),
- c.getParameterTypes(),
- c.getExceptionTypes(),
- c.getModifiers());
- parent.setDelegate(acc);
- }
- // 调用native方法,进行调用 constructor
- return newInstance0(c, args);
- }
返回构造器的实例后,可以根据外部进行进行类型转换,从而使用接口或方法进行调用实例功能了。
2. 反射获取方法 c.class.getDeclaredMethod();Method.invoke() 反射调用方法!
第一步,先获取 Method;
- // java.lang.Class
- @CallerSensitive
- 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. 获取所有方法列表;
2. 根据方法名称和方法列表,选出符合要求的方法;
3. 如果没有找到相应方法,抛出异常,否则返回对应方法;
所以,先看一下怎样获取类声明的所有方法?
- // Returns an array of "root" methods. These Method objects must NOT
- // be propagated to the outside world, but must instead be copied
- // via ReflectionFactory.copyMethod.
- 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中获取!
不同的是,方法列表需要进行过滤 Reflection.filterMethods;当然后面看来,这个方法我们一般不会派上用场!
- // sun.misc.Reflection
- public static Method[] filterMethods(Class<?> containingClass, Method[] methods) {
- if (methodFilterMap == null) {
- // Bootstrapping
- return methods;
- }
- return (Method[])filter(methods, methodFilterMap.get(containingClass));
- }
- // 可以过滤指定的方法,一般为空,如果要指定过滤,可以调用 registerMethodsToFilter(), 或者...
- private static Member[] filter(Member[] members, String[] filteredNames) {
- if ((filteredNames == null) || (members.length == 0)) {
- return members;
- }
- int numNewMembers = 0;
- for (Member member : members) {
- boolean shouldSkip = false;
- for (String filteredName : filteredNames) {
- if (member.getName() == filteredName) {
- shouldSkip = true;
- break;
- }
- }
- if (!shouldSkip) {
- ++numNewMembers;
- }
- }
- Member[] newMembers =
- (Member[])Array.newInstance(members[0].getClass(), numNewMembers);
- int destIdx = 0;
- for (Member member : members) {
- boolean shouldSkip = false;
- for (String filteredName : filteredNames) {
- if (member.getName() == filteredName) {
- shouldSkip = true;
- break;
- }
- }
- if (!shouldSkip) {
- newMembers[destIdx++] = member;
- }
- }
- return newMembers;
- }
第二步,根据方法名和参数类型过滤指定方法返回:
- private static Method searchMethods(Method[] methods,
- String name,
- Class<?>[] parameterTypes)
- {
- Method res = null;
- // 使用常量池,避免重复创建String
- String internedName = name.intern();
- for (int i = 0; i < methods.length; i++) {
- Method m = methods[i];
- if (m.getName() == internedName
- && arrayContentsEq(parameterTypes, m.getParameterTypes())
- && (res == null
- || res.getReturnType().isAssignableFrom(m.getReturnType())))
- res = m;
- }
- return (res == null ? res : getReflectionFactory().copyMethod(res));
- }
大概意思看得明白,就是匹配到方法名,然后参数类型匹配,才可以!
但是,可以看到,匹配到一个方法,并没有退出for循环,而是继续进行匹配!
这里,是匹配最精确的子类进行返回(最优匹配)
最后,还是通过 ReflectionFactory, copy 方法后返回!
第三步,调用 method.invoke() 方法!
- @CallerSensitive
- 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);
- }
invoke时,是通过 MethodAccessor 进行调用的,而 MethodAccessor 是个接口,在第一次时调用 acquireMethodAccessor() 进行新创建!
- // probably make the implementation more scalable.
- 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,否则调用 ReflectionFactory 创建新的 MethodAccessor
- methodAccessor = tmp;
- } else {
- // Otherwise fabricate one and propagate it up to the root
- tmp = reflectionFactory.newMethodAccessor(this);
- setMethodAccessor(tmp);
- }
- return tmp;
- }
- // sun.reflect.ReflectionFactory
- public MethodAccessor newMethodAccessor(Method method) {
- checkInitted();
- 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;
- }
- }
两个Accessor详情:
- // NativeMethodAccessorImpl / DelegatingMethodAccessorImpl
- 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
- {
- // We can't inflate methods belonging to vm-anonymous classes because
- // that kind of class can't be referred to by name, hence can't be
- // found from the generated bytecode.
- if (++numInvocations > ReflectionFactory.inflationThreshold()
- && !ReflectUtil.isVMAnonymousClass(method.getDeclaringClass())) {
- 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);
- }
- void setParent(DelegatingMethodAccessorImpl parent) {
- this.parent = parent;
- }
- private static native Object invoke0(Method m, Object obj, Object[] args);
- }
- class DelegatingMethodAccessorImpl extends MethodAccessorImpl {
- private MethodAccessorImpl delegate;
- DelegatingMethodAccessorImpl(MethodAccessorImpl delegate) {
- setDelegate(delegate);
- }
- public Object invoke(Object obj, Object[] args)
- throws IllegalArgumentException, InvocationTargetException
- {
- return delegate.invoke(obj, args);
- }
- void setDelegate(MethodAccessorImpl delegate) {
- this.delegate = delegate;
- }
- }
进行 ma.invoke(obj, args); 调用时,调用 DelegatingMethodAccessorImpl.invoke();
最后被委托到 NativeMethodAccessorImpl.invoke(), 即:
- public Object invoke(Object obj, Object[] args)
- throws IllegalArgumentException, InvocationTargetException
- {
- // We can't inflate methods belonging to vm-anonymous classes because
- // that kind of class can't be referred to by name, hence can't be
- // found from the generated bytecode.
- if (++numInvocations > ReflectionFactory.inflationThreshold()
- && !ReflectUtil.isVMAnonymousClass(method.getDeclaringClass())) {
- MethodAccessorImpl acc = (MethodAccessorImpl)
- new MethodAccessorGenerator().
- generateMethod(method.getDeclaringClass(),
- method.getName(),
- method.getParameterTypes(),
- method.getReturnType(),
- method.getExceptionTypes(),
- method.getModifiers());
- parent.setDelegate(acc);
- }
- // invoke0 是个 native 方法,由jvm进行调用业务方法!从而完成反射调用功能!
- return invoke0(method, obj, args);
- }
其中, generateMethod() 是生成具体类的方法:
- /** This routine is not thread-safe */
- public MethodAccessor generateMethod(Class<?> declaringClass,
- String name,
- Class<?>[] parameterTypes,
- Class<?> returnType,
- Class<?>[] checkedExceptions,
- int modifiers)
- {
- return (MethodAccessor) generate(declaringClass,
- name,
- parameterTypes,
- returnType,
- checkedExceptions,
- modifiers,
- false,
- false,
- null);
- }
generate() 戳详情!
- /** This routine is not thread-safe */
- private MagicAccessorImpl generate(final Class<?> declaringClass,
- String name,
- Class<?>[] parameterTypes,
- Class<?> returnType,
- Class<?>[] checkedExceptions,
- int modifiers,
- boolean isConstructor,
- boolean forSerialization,
- Class<?> serializationTargetClass)
- {
- ByteVector vec = ByteVectorFactory.create();
- asm = new ClassFileAssembler(vec);
- this.declaringClass = declaringClass;
- this.parameterTypes = parameterTypes;
- this.returnType = returnType;
- this.modifiers = modifiers;
- this.isConstructor = isConstructor;
- this.forSerialization = forSerialization;
- asm.emitMagicAndVersion();
- // Constant pool entries:
- // ( * = Boxing information: optional)
- // (+ = Shared entries provided by AccessorGenerator)
- // (^ = Only present if generating SerializationConstructorAccessor)
- // [UTF-8] [This class's name]
- // [CONSTANT_Class_info] for above
- // [UTF-8] "sun/reflect/{MethodAccessorImpl,ConstructorAccessorImpl,SerializationConstructorAccessorImpl}"
- // [CONSTANT_Class_info] for above
- // [UTF-8] [Target class's name]
- // [CONSTANT_Class_info] for above
- // ^ [UTF-8] [Serialization: Class's name in which to invoke constructor]
- // ^ [CONSTANT_Class_info] for above
- // [UTF-8] target method or constructor name
- // [UTF-8] target method or constructor signature
- // [CONSTANT_NameAndType_info] for above
- // [CONSTANT_Methodref_info or CONSTANT_InterfaceMethodref_info] for target method
- // [UTF-8] "invoke" or "newInstance"
- // [UTF-8] invoke or newInstance descriptor
- // [UTF-8] descriptor for type of non-primitive parameter 1
- // [CONSTANT_Class_info] for type of non-primitive parameter 1
- // ...
- // [UTF-8] descriptor for type of non-primitive parameter n
- // [CONSTANT_Class_info] for type of non-primitive parameter n
- // + [UTF-8] "java/lang/Exception"
- // + [CONSTANT_Class_info] for above
- // + [UTF-8] "java/lang/ClassCastException"
- // + [CONSTANT_Class_info] for above
- // + [UTF-8] "java/lang/NullPointerException"
- // + [CONSTANT_Class_info] for above
- // + [UTF-8] "java/lang/IllegalArgumentException"
- // + [CONSTANT_Class_info] for above
- // + [UTF-8] "java/lang/InvocationTargetException"
- // + [CONSTANT_Class_info] for above
- // + [UTF-8] "<init>"
- // + [UTF-8] "()V"
- // + [CONSTANT_NameAndType_info] for above
- // + [CONSTANT_Methodref_info] for NullPointerException's constructor
- // + [CONSTANT_Methodref_info] for IllegalArgumentException's constructor
- // + [UTF-8] "(Ljava/lang/String;)V"
- // + [CONSTANT_NameAndType_info] for "<init>(Ljava/lang/String;)V"
- // + [CONSTANT_Methodref_info] for IllegalArgumentException's constructor taking a String
- // + [UTF-8] "(Ljava/lang/Throwable;)V"
- // + [CONSTANT_NameAndType_info] for "<init>(Ljava/lang/Throwable;)V"
- // + [CONSTANT_Methodref_info] for InvocationTargetException's constructor
- // + [CONSTANT_Methodref_info] for "super()"
- // + [UTF-8] "java/lang/Object"
- // + [CONSTANT_Class_info] for above
- // + [UTF-8] "toString"
- // + [UTF-8] "()Ljava/lang/String;"
- // + [CONSTANT_NameAndType_info] for "toString()Ljava/lang/String;"
- // + [CONSTANT_Methodref_info] for Object's toString method
- // + [UTF-8] "Code"
- // + [UTF-8] "Exceptions"
- // * [UTF-8] "java/lang/Boolean"
- // * [CONSTANT_Class_info] for above
- // * [UTF-8] "(Z)V"
- // * [CONSTANT_NameAndType_info] for above
- // * [CONSTANT_Methodref_info] for above
- // * [UTF-8] "booleanValue"
- // * [UTF-8] "()Z"
- // * [CONSTANT_NameAndType_info] for above
- // * [CONSTANT_Methodref_info] for above
- // * [UTF-8] "java/lang/Byte"
- // * [CONSTANT_Class_info] for above
- // * [UTF-8] "(B)V"
- // * [CONSTANT_NameAndType_info] for above
- // * [CONSTANT_Methodref_info] for above
- // * [UTF-8] "byteValue"
- // * [UTF-8] "()B"
- // * [CONSTANT_NameAndType_info] for above
- // * [CONSTANT_Methodref_info] for above
- // * [UTF-8] "java/lang/Character"
- // * [CONSTANT_Class_info] for above
- // * [UTF-8] "(C)V"
- // * [CONSTANT_NameAndType_info] for above
- // * [CONSTANT_Methodref_info] for above
- // * [UTF-8] "charValue"
- // * [UTF-8] "()C"
- // * [CONSTANT_NameAndType_info] for above
- // * [CONSTANT_Methodref_info] for above
- // * [UTF-8] "java/lang/Double"
- // * [CONSTANT_Class_info] for above
- // * [UTF-8] "(D)V"
- // * [CONSTANT_NameAndType_info] for above
- // * [CONSTANT_Methodref_info] for above
- // * [UTF-8] "doubleValue"
- // * [UTF-8] "()D"
- // * [CONSTANT_NameAndType_info] for above
- // * [CONSTANT_Methodref_info] for above
- // * [UTF-8] "java/lang/Float"
- // * [CONSTANT_Class_info] for above
- // * [UTF-8] "(F)V"
- // * [CONSTANT_NameAndType_info] for above
- // * [CONSTANT_Methodref_info] for above
- // * [UTF-8] "floatValue"
- // * [UTF-8] "()F"
- // * [CONSTANT_NameAndType_info] for above
- // * [CONSTANT_Methodref_info] for above
- // * [UTF-8] "java/lang/Integer"
- // * [CONSTANT_Class_info] for above
- // * [UTF-8] "(I)V"
- // * [CONSTANT_NameAndType_info] for above
- // * [CONSTANT_Methodref_info] for above
- // * [UTF-8] "intValue"
- // * [UTF-8] "()I"
- // * [CONSTANT_NameAndType_info] for above
- // * [CONSTANT_Methodref_info] for above
- // * [UTF-8] "java/lang/Long"
- // * [CONSTANT_Class_info] for above
- // * [UTF-8] "(J)V"
- // * [CONSTANT_NameAndType_info] for above
- // * [CONSTANT_Methodref_info] for above
- // * [UTF-8] "longValue"
- // * [UTF-8] "()J"
- // * [CONSTANT_NameAndType_info] for above
- // * [CONSTANT_Methodref_info] for above
- // * [UTF-8] "java/lang/Short"
- // * [CONSTANT_Class_info] for above
- // * [UTF-8] "(S)V"
- // * [CONSTANT_NameAndType_info] for above
- // * [CONSTANT_Methodref_info] for above
- // * [UTF-8] "shortValue"
- // * [UTF-8] "()S"
- // * [CONSTANT_NameAndType_info] for above
- // * [CONSTANT_Methodref_info] for above
- short numCPEntries = NUM_BASE_CPOOL_ENTRIES + NUM_COMMON_CPOOL_ENTRIES;
- boolean usesPrimitives = usesPrimitiveTypes();
- if (usesPrimitives) {
- numCPEntries += NUM_BOXING_CPOOL_ENTRIES;
- }
- if (forSerialization) {
- numCPEntries += NUM_SERIALIZATION_CPOOL_ENTRIES;
- }
- // Add in variable-length number of entries to be able to describe
- // non-primitive parameter types and checked exceptions.
- numCPEntries += (short) (2 * numNonPrimitiveParameterTypes());
- asm.emitShort(add(numCPEntries, S1));
- final String generatedName = generateName(isConstructor, forSerialization);
- asm.emitConstantPoolUTF8(generatedName);
- asm.emitConstantPoolClass(asm.cpi());
- thisClass = asm.cpi();
- if (isConstructor) {
- if (forSerialization) {
- asm.emitConstantPoolUTF8
- ("sun/reflect/SerializationConstructorAccessorImpl");
- } else {
- asm.emitConstantPoolUTF8("sun/reflect/ConstructorAccessorImpl");
- }
- } else {
- asm.emitConstantPoolUTF8("sun/reflect/MethodAccessorImpl");
- }
- asm.emitConstantPoolClass(asm.cpi());
- superClass = asm.cpi();
- asm.emitConstantPoolUTF8(getClassName(declaringClass, false));
- asm.emitConstantPoolClass(asm.cpi());
- targetClass = asm.cpi();
- short serializationTargetClassIdx = (short) 0;
- if (forSerialization) {
- asm.emitConstantPoolUTF8(getClassName(serializationTargetClass, false));
- asm.emitConstantPoolClass(asm.cpi());
- serializationTargetClassIdx = asm.cpi();
- }
- asm.emitConstantPoolUTF8(name);
- asm.emitConstantPoolUTF8(buildInternalSignature());
- asm.emitConstantPoolNameAndType(sub(asm.cpi(), S1), asm.cpi());
- if (isInterface()) {
- asm.emitConstantPoolInterfaceMethodref(targetClass, asm.cpi());
- } else {
- if (forSerialization) {
- asm.emitConstantPoolMethodref(serializationTargetClassIdx, asm.cpi());
- } else {
- asm.emitConstantPoolMethodref(targetClass, asm.cpi());
- }
- }
- targetMethodRef = asm.cpi();
- if (isConstructor) {
- asm.emitConstantPoolUTF8("newInstance");
- } else {
- asm.emitConstantPoolUTF8("invoke");
- }
- invokeIdx = asm.cpi();
- if (isConstructor) {
- asm.emitConstantPoolUTF8("([Ljava/lang/Object;)Ljava/lang/Object;");
- } else {
- asm.emitConstantPoolUTF8
- ("(Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;");
- }
- invokeDescriptorIdx = asm.cpi();
- // Output class information for non-primitive parameter types
- nonPrimitiveParametersBaseIdx = add(asm.cpi(), S2);
- for (int i = 0; i < parameterTypes.length; i++) {
- Class<?> c = parameterTypes[i];
- if (!isPrimitive(c)) {
- asm.emitConstantPoolUTF8(getClassName(c, false));
- asm.emitConstantPoolClass(asm.cpi());
- }
- }
- // Entries common to FieldAccessor, MethodAccessor and ConstructorAccessor
- emitCommonConstantPoolEntries();
- // Boxing entries
- if (usesPrimitives) {
- emitBoxingContantPoolEntries();
- }
- if (asm.cpi() != numCPEntries) {
- throw new InternalError("Adjust this code (cpi = " + asm.cpi() +
- ", numCPEntries = " + numCPEntries + ")");
- }
- // Access flags
- asm.emitShort(ACC_PUBLIC);
- // This class
- asm.emitShort(thisClass);
- // Superclass
- asm.emitShort(superClass);
- // Interfaces count and interfaces
- asm.emitShort(S0);
- // Fields count and fields
- asm.emitShort(S0);
- // Methods count and methods
- asm.emitShort(NUM_METHODS);
- emitConstructor();
- emitInvoke();
- // Additional attributes (none)
- asm.emitShort(S0);
- // Load class
- vec.trim();
- final byte[] bytes = vec.getData();
- // Note: the class loader is the only thing that really matters
- // here -- it's important to get the generated code into the
- // same namespace as the target class. Since the generated code
- // is privileged anyway, the protection domain probably doesn't
- // matter.
- return AccessController.doPrivileged(
- new PrivilegedAction<MagicAccessorImpl>() {
- public MagicAccessorImpl run() {
- try {
- return (MagicAccessorImpl)
- ClassDefiner.defineClass
- (generatedName,
- bytes,
- 0,
- bytes.length,
- declaringClass.getClassLoader()).newInstance();
- } catch (InstantiationException | IllegalAccessException e) {
- throw new InternalError(e);
- }
- }
- });
- }
咱们主要看这一句:ClassDefiner.defineClass(xx, declaringClass.getClassLoader()).newInstance();
在ClassDefiner.defineClass方法实现中,每被调用一次都会生成一个DelegatingClassLoader类加载器对象 ,这里每次都生成新的类加载器,是为了性能考虑,在某些情况下可以卸载这些生成的类,因为类的卸载是只有在类加载器可以被回收的情况下才会被回收的,如果用了原来的类加载器,那可能导致这些新创建的类一直无法被卸载!
而反射生成的类,有时候可能用了就可以卸载了,所以使用其独立的类加载器,从而使得更容易控制反射类的生命周期!
最后,用几句话总结反射的实现原理:
1. 反射类及反射方法的获取,都是通过从列表中搜寻查找匹配的方法,所以查找性能会随类的大小方法多少而变化;
2. 每个类都会有一个与之对应的Class实例,从而每个类都可以获取method反射方法,并作用到其他实例身上;
3. 反射也是考虑了线程安全的,放心使用;
4. 反射使用软引用relectionData缓存class信息,避免每次重新从jvm获取带来的开销;
5. 反射调用多次生成新代理Accessor, 而通过字节码生存的则考虑了卸载功能,所以会使用独立的类加载器;
6. 当找到需要的方法,都会copy一份出来,而不是使用原来的实例,从而保证数据隔离;
7. 调度反射方法,最终是由jvm执行invoke0()执行;
深入理解java反射原理的更多相关文章
- 《深入理解Java虚拟机》虚拟机性能监控与故障处理工具
上节学习回顾 从课本章节划分,<垃圾收集器>和<内存分配策略>这两篇随笔同属一章节,主要是从理论+实验的手段来讲解JVM的内存处理机制.好让我们对JVM运行机制有一个良好的概念 ...
- 深入理解Java 8 Lambda(语言篇——lambda,方法引用,目标类型和默认方法)
作者:Lucida 微博:@peng_gong 豆瓣:@figure9 原文链接:http://zh.lucida.me/blog/java-8-lambdas-insideout-language- ...
- java笔记--理解java类加载器以及ClassLoader类
类加载器概述: java类的加载是由虚拟机来完成的,虚拟机把描述类的Class文件加载到内存,并对数据进行校验,解析和初始化,最终形成能被java虚拟机直接使用的java类型,这就是虚拟机的类加载机制 ...
- 《深入理解Java内存模型》读书总结
概要 文章是<深入理解Java内容模型>读书笔记,该书总共包括了3部分的知识. 第1部分,基本概念 包括"并发.同步.主内存.本地内存.重排序.内存屏障.happens befo ...
- 深入理解Java的接口和抽象类(转)
深入理解Java的接口和抽象类 对于面向对象编程来说,抽象是它的一大特征之一.在Java中,可以通过两种形式来体现OOP的抽象:接口和抽象类.这两者有太多相似的地方,又有太多不同的地方.很多人在初学的 ...
- 《深入理解 java虚拟机》学习笔记
java内存区域详解 以下内容参考自<深入理解 java虚拟机 JVM高级特性与最佳实践>,其中图片大多取自网络与本书,以供学习和参考.
- 【转】深入理解 Java 垃圾回收机制
深入理解 Java 垃圾回收机制 一.垃圾回收机制的意义 Java语言中一个显著的特点就是引入了垃圾回收机制,使c++程序员最头疼的内存管理的问题迎刃而解,它使得Java程序员在编写程序的时候不再 ...
- 深入理解java内存模型系列文章
转载关于java内存模型的系列文章,写的非常好. 深入理解java内存模型(一)--基础 深入理解java内存模型(二)--重排序 深入理解java内存模型(三)--顺序一致性 深入理解java内存模 ...
- 深入理解Java的接口和抽象类
深入理解Java的接口和抽象类 对于面向对象编程来说,抽象是它的一大特征之一.在Java中,可以通过两种形式来体现OOP的抽象:接口和抽象类.这两者有太多相似的地方,又有太多不同的地方.很多人在初学的 ...
随机推荐
- springmvc webservlet 异步请求总结
1:每次请求会启动一个新线程 上边在debug状态下, 每次请求一次,生成一个新的 thread 在此已经是245了 出现一个现象在debug模式下, 每次请求生成的线程,自动在红框那个位置停了下来 ...
- 常用的三种json软件的使用
从几个角度比较三种软件 1. json操作 2 反解 3 性能 易用性还没有列出. 可以根据个人喜好进行取舍. package json; import com.alibaba.fastjson.JS ...
- Cannot retrieve metalink for repository: epel/x86_64. Please verify its path and try again
虚拟机恢复快照后,使用yum安装软件,提示下面的信息,开始以为是yum源的问题或者DNS的问题,但是无果,最后再看一下服务器的时间,坑了,还原快照,时间变成以前的了. [root@localhost ...
- 464. Can I Win
https://leetcode.com/problems/can-i-win/description/ In the "100 game," two players take t ...
- Innodb 状态的部分解释
Innodb_buffer_pool_pages_data Innodb buffer pool缓存池中包含数据的页的数目,包括脏页.单位是page. Innodb_buffer_pool_pages ...
- 别人的Linux私房菜(17)进程管理与SELinux初探
程序在磁盘中,通过用户的执行触发.触发事件时,加载到内存,系统将它定义成进程,给予进程PID,根据触发的用户和属性,给予PID合适的权限. PID和登陆者的UID/GID有关.父进程衍生出来的进程为子 ...
- django的视图函数
一.视图函数view 视图函数是接收一个请求(request对象),并返回响应的函数 1. HttpResponse响应请求 这个方法是返回字符串一类的,可以识别标签 2. render响应请求 re ...
- flume接收http请求,并将数据写到kafka
flume接收http请求,并将数据写到kafka,spark消费kafka的数据.是数据采集的经典框架. 直接上flume的配置: source : http channel : file sink ...
- 解决css冲突的问题
在各个框架中,每个例子都会自带一些样式. 拼接的时候都是全局的,或者同样修改了某个地方,就会产生冲突. 方法一: 首先导入全局,然后再导入其他的进行覆盖 方法二: 给样式添加作用域,只要当前作用域中起 ...
- mysql 截取替换某个字符串
SELECT m.content,o.order_price,o.id,m.id FROM scp_home_msg m INNER JOIN scp_order o ON m.link_id=o.i ...