JAVA反射中Class类源码分析

这篇博客主要是来分析下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;
    }

1、checkInitted() 来判断是否配置了useCached属性,通过sun.reflect.noCaches来配置,如果配置的话,将useCached改为配置的属性

2、reflectionData()获取缓存当中的数据,如果缓存当中有数据,直接返回缓存当中的构造方法

3、如果缓存当中没有数据,就从JVM当中读取数据

4、如果是接口类型,直接生成一个数组长度为0的Constructor数组,因为接口没有构造方法

5、如果不是接口类型,从JVM当中获取getDeclaredConstructors0 是native方法

6、最后更新缓存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);
    }

1、首先获取当前reflectionData

2、如果可以使用缓存,并且缓存当中的数据不为null,而且缓存没有失效,(缓存当中redefinedCount等于classRedefinedCount的值),直接返回缓存当中的reflectionData

3、如果以上都不是的话,就创建新的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;
            }
        }
    }

1、首先,还是判断是否使用缓存,如果不使用,直接返回

2、使用while+CAS方式更新数据,创建一个新的ReflectionData,如果更新成功直接返回,否则进入3

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;
    }

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;
        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;
    }

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方式的分析和执行结果其实是错误的,两者都是只执行静态代码块。

猜你喜欢

转载自blog.csdn.net/pange1991/article/details/81303454