美文网首页
java菜鸟到大佬——全网最全反射机制讲解

java菜鸟到大佬——全网最全反射机制讲解

作者: 415e09c8f81f | 来源:发表于2022-10-17 09:38 被阅读0次

    目录:

    一.反射基础

    二.反射的作用

    三.反射机制执行的流程

    一.反射基础

    什么是反射?

    反射使 Java 代码可以发现有关已加载类的字段,方法和构造函数的信息,并在安全性限制内使用反射对这些字段,方法和构造函数进行操作。

    反射的概念是由Smith在1982年首次提出的,主要是指程序可以访问、检测和修改它本身状态或行为的一种能力。这一概念的提出很快引发了计算机科学领域关于应用反射性的研究。它首先被程序语言的设计领域所采用,并在Lisp和面向对象方面取得了成绩。其中LEAD/LEAD++ 、OpenC++ 、MetaXa和OpenJava等就是基于反射机制的语言。最近,反射机制也被应用到了视窗系统、操作系统和文件系统中。

    Java中,反射是一种强大的工具。它使您能够创建灵活的代码,这些代码可以在运行时装配,无需在组件之间进行源代表链接。反射允许我们在编写与执行时,使我们的程序代码能够接入装载到JVM中的类的内部信息,而不是源代码中选定的类协作的代码。这使反射成为构建灵活的应用的主要工具。但需注意的是:如果使用不当,反射的成本很高。

    简而言之,指在 Java 程序运行时

    • 给定的一个类(Class)对象,通过反射获取这个类(Class)对象的所有成员结构。
    • 给定的一个具体的对象,能够动态地调用它的方法及对任意属性值进行获取和赋值。

    这种动态获取类的内容,创建对象、以及动态调用对象的方法及操作属性的机制为反射。即使该对象的类型在编译期间是未知,该类的 .class 文件不存在,也可以通过反射直接创建对象。

    优势

    • 增加程序的灵活性,避免将固有的逻辑程序写死到代码里
    • 代码简洁,可读性强,可提高代码的复用率

    劣势

    • 相较直接调用,在量大的情景下反射性能下降
    • 存在一些内部暴露和安全隐患

    为什么要有反射

    有了反射,我们可以做以下事情:

    • 在运行时检查一个对象
    • 在运行时,根据一个class构造一个对象
    • 在运行时,检查一个对象的属性和方法
    • 在运行时,调用一个对象的任意一个方法
    • 在运行时,改变对象的构造函数,属性,方法的可见性等等

    反射是很多框架的共有的方法:

    • 例如JUnit,就是使用反射去找出那些带有@Test注解的方法,然后就利用反射在单元测试中调用这些方法
    • 在web框架中,开发人员将他们定义实现的接口和类放到配置文件中,使用反射,他可以动态地在运行时自动初始化这些类和接口 例如,Spring中一般这样使用配置文件:

    <bean id="someID" class="com.programcreek.Foo">

    <property name="someField" value="someValue" /></bean>

    当Spring读取到bean文件的时候,会调用Class.forName(String)方法"com.programcreek.Foo"来初始化这个类,然后在使用反射正确的get到所配置的属性的set方法,并把相应的值set进去。

    Servlet web 也是使用这种反射技术:

    <servlet>

    <servlet-name>someServlet</servlet-name>

    <servlet-class>com.programcreek.WhyReflectionServlet</servlet-class><servlet>

    反射的原理(类加载)

    关于类加载机制,大家可以参考我的这篇文章:

    深入理解JVM虚拟机——类的加载机制

    深入理解JVM虚拟机——JVM是如何实现反射的?

    类加载机制流程

    类的加载

    反射的原理图解

    二. 反射的作用

    一个类的成员包括以下三种:域信息、构造器信息、方法信息。而反射则可以在运行时动态获取到这些信息,在使用反射时,我们常用的类有以下五种。

    Class类对象的获取

    1、获得Class:主要有三种方法:

    (1)Object–>getClass

    (2)任何数据类型(包括基本的数据类型)都有一个“静态”的class属性

    (3)通过class类的静态方法:forName(String className)(最常用)

    package fanshe;
    
    public class Fanshe {
    
        public static void main(String[] args) {
    
           //第一种方式获取Class对象
            Student stu1 = new Student();//这一new 产生一个Student对象,一个Class对象。
    
            Class stuClass = stu1.getClass();//获取Class对象
    
            System.out.println(stuClass.getName());
          
    
           //第二种方式获取Class对象
            Class stuClass2 = Student.class;
    
            System.out.println(stuClass == stuClass2);//判断第一种方式获取的Class对象和第二种方式获取的是否是同一个
    
          
          //第三种方式获取Class对象
            try {
    
                Class stuClass3 = Class.forName("fanshe.Student");//注意此字符串必须是真实路径,就是带包名的类路径,包名.类名
    
                System.out.println(stuClass3 == stuClass2);//判断三种方式是否获取的是同一个Class对象
    
            } catch (ClassNotFoundException e) {
    
                e.printStackTrace();
    
            }
    
        }
    }

    注意,在运行期间,一个类,只有一个Class对象产生,所以打印结果都是true;

    三种方式中,常用第三种,第一种对象都有了还要反射干什么,第二种需要导入类包,依赖太强,不导包就抛编译错误。一般都使用第三种,一个字符串可以传入也可以写在配置文件中等多种方法。

    Class类的方法

    getName、getCanonicalName与getSimpleName的区别

    • getSimpleName:只获取类名
    • getName:类的全限定名,jvm中Class的表示,可以用于动态加载Class对象,例如Class.forName。
    • getCanonicalName:返回更容易理解的表示,主要用于输出(toString)或log打印,大多数情况下和getName一样,但是在内部类、数组等类型的表示形式就不同了。

    Constructor类及其获取对象方法

    • Constructor提供了一个类的单个构造函数的信息和访问。
    • Constructor允许在将实际参数与newInstance()与底层构造函数的形式参数进行匹配时进行扩展转换,但如果发生缩小转换,则抛出IllegalArgumentException 。

    Constructor类的方法

    获取Constructor对象是通过Class类中的方法获取的,Class类与Constructor相关的主要方法如下:

    使用反射技术获取构造器对象并使用

    @Test
    public void test2() throws NoSuchMethodException {
        Class<Student> sc = Student.class;
         // 1. 拿到所有的构造器
        Constructor<?>[] constructors = sc.getDeclaredConstructors();
        // 输出构造器的名称+参数个数
        for (Constructor<?> constructor : constructors) {
            System.out.println(constructor.getName() + " 参数个数:" + constructor.getParameterCount() + "个");
        }
        // 2. 拿到单个构造器
        Constructor<Student> constructor = sc.getDeclaredConstructor(String.class, String.class);
        System.out.println(constructor.getName() + "参数个数:" + constructor.getParameterCount());
    }

    使用反射技术获取构造器对象并使用获取到的内容创建出一个对象

    反射得到构造器之后的作用仍是创建一个对象,如果说构造器是public,就可以直接new对象,如果说是构造器是私有的private,需要提前将构造器进行暴力反射,再进行构造对象。

    反射是可以直接破换掉封装性的,私有的也是可以执行的。

    Field类及其用法

    Field 提供有关类或接口的单个字段的信息,以及对它的动态访问权限。反射的字段可能是一个类(静态)字段或实例字段。

    Field类涉及的get方法

    同样的道理,我们可以通过Class类的提供的方法来获取代表字段信息的Field对象,Class类与Field对象相关方法如下:

    下面的代码演示了上述方法的使用过程

    public class ReflectField {
    
        public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException {
    
            Class<?> clazz = Class.forName("reflect.Student");
    
            //获取指定字段名称的Field类,注意字段修饰符必须为public而且存在该字段,
    
            // 否则抛NoSuchFieldException
    
            Field field = clazz.getField("age");
    
            System.out.println("field:" + field);
    
           //获取所有修饰符为public的字段,包含父类字段,注意修饰符为public才会获取
    
            Field fields[] = clazz.getFields();
    
            for (Field f : fields) {
    
                System.out.println("f:" + f.getDeclaringClass());
    
            }
    
            System.out.println("================getDeclaredFields====================");
    
            //获取当前类所字段(包含private字段),注意不包含父类的字段
    
            Field fields2[] = clazz.getDeclaredFields();
    
            for (Field f : fields2) {
    
                System.out.println("f2:" + f.getDeclaringClass());
    
            }
    
            //获取指定字段名称的Field类,可以是任意修饰符的自动,注意不包含父类的字段
    
            Field field2 = clazz.getDeclaredField("desc");
    
            System.out.println("field2:" + field2);
    
        }
    
    /**
    
     输出结果:
    
     field:public int reflect.Person.age
    
     f:public java.lang.String reflect.Student.desc
    
     f:public int reflect.Person.age
    
     f:public java.lang.String reflect.Person.name
    
     ================getDeclaredFields====================
    
     f2:public java.lang.String reflect.Student.desc
    
     f2:private int reflect.Student.score
    
     field2:public java.lang.String reflect.Student.desc
    
     */
    }
    
    class Person {
    
        public int age;
    
        public String name;
    
    //省略set和get方法}
    
        class Student extends Person {
    
            public String desc;
    
            private int score;
            //省略set和get方法
        }

    上述方法需要注意的是,如果我们不期望获取其父类的字段,则需使用Class类的getDeclaredField/getDeclaredFields方法来获取字段即可,倘若需要连带获取到父类的字段,那么请使用Class类的getField/getFields,但是也只能获取到public修饰的的字段,无法获取父类的私有字段。下面将通过Field类本身的方法对指定类属性赋值,代码演示如下:

    //获取Class对象引用

    Class<?> clazz = Class.forName("reflect.Student");

    Student st= (Student) clazz.newInstance();

    //获取父类public字段并赋值

    Field ageField = clazz.getField("age");

    ageField.set(st,18);

    Field nameField = clazz.getField("name");

    nameField.set(st,"Lily");

    //只获取当前类的字段,不获取父类的字段

    Field descField = clazz.getDeclaredField("desc");

    descField.set(st,"I am student");Field scoreField = clazz.getDeclaredField("score");

    //设置可访问,score是private的

    scoreField.setAccessible(true);

    scoreField.set(st,88);System.out.println(st.toString());

    //输出结果:Student{age=18, name='Lily ,desc='I am student', score=88}

    //获取字段值System.out.println(scoreField.get(st));// 88

    其中的set(Object obj, Object value)方法是Field类本身的方法,用于设置字段的值,而get(Object obj)则是获取字段的值,当然关于Field类还有其他常用的方法如下:

    上述方法可能是较为常用的,事实上在设置值的方法上,Field类还提供了专门针对基本数据类型的方法,如setInt()/getInt()、setBoolean()/getBoolean、setChar()/getChar()等等方法,这里就不全部列出了,需要时查API文档即可。需要特别注意的是被final关键字修饰的Field字段是安全的,在运行时可以接收任何修改,但最终其实际值是不会发生改变的。

    Method类及其用法

    Method 提供关于类或接口上单独某个方法(以及如何访问该方法)的信息,所反映的方法可能是类方法或实例方法(包括抽象方法)。

    Method类的主要方法

    下面是Class类获取Method对象相关的方法:

    同样通过案例演示上述方法:

    import java.lang.reflect.Method;
    
    public class ReflectMethod {
    
        public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException {
    
            Class clazz = Class.forName("reflect.Circle");
    
           //根据参数获取public的Method,包含继承自父类的方法
    
            Method method = clazz.getMethod("draw", int.class, String.class);
    
            System.out.println("method:" + method);
    
           //获取所有public的方法:
    
            Method[] methods = clazz.getMethods();
    
            for (Method m : methods) {
    
                System.out.println("m::" + m);
    
            }
    
            System.out.println("=========================================");
    
            //获取当前类的方法包含private,该方法无法获取继承自父类的method
    
            Method method1 = clazz.getDeclaredMethod("drawCircle");
    
            System.out.println("method1::" + method1);
    
           //获取当前类的所有方法包含private,该方法无法获取继承自父类的method
    
            Method[] methods1 = clazz.getDeclaredMethods();
    
            for (Method m : methods1) {
    
                System.out.println("m1::" + m);
    
            }
    
        }
    }
    
    class Shape {
    
        public void draw() {
    
            System.out.println("draw");
    
        }
    
        public void draw(int count, String name) {
    
            System.out.println("draw " + name + ",count=" + count);
    
        }
    
    }
    
    class Circle extends Shape {
    
        private void drawCircle() {
    
            System.out.println("drawCircle");
    
        }
    
        public int getAllCount() {
    
            return 100;
    
        }
    }
    
    

    输出结果:

    method:public void reflect.Shape.draw(int,java.lang.String)

    m::public int reflect.Circle.getAllCount()

    m::public void reflect.Shape.draw()

    m::public void reflect.Shape.draw(int,java.lang.String)

    m::public final void java.lang.Object.wait(long,int) throws java.lang.InterruptedException

    m::public final native void java.lang.Object.wait(long) throws java.lang.InterruptedException

    m::public final void java.lang.Object.wait() throws java.lang.InterruptedException

    m::public boolean java.lang.Object.equals(java.lang.Object)

    m::public java.lang.String java.lang.Object.toString()

    m::public native int java.lang.Object.hashCode()

    m::public final native java.lang.Class java.lang.Object.getClass()

    m::public final native void java.lang.Object.notify()

    m::public final native void java.lang.Object.notifyAll()

    =========================================

    method1::private void reflect.Circle.drawCircle()

    m1::public int reflect.Circle.getAllCount()

    m1::private void reflect.Circle.drawCircle()

    在通过getMethods方法获取Method对象时,会把父类的方法也获取到,如上的输出结果,把Object类的方法都打印出来了。而getDeclaredMethod/getDeclaredMethods方法都只能获取当前类的方法。我们在使用时根据情况选择即可。下面将演示通过Method对象调用指定类的方法:

    Class clazz = Class.forName("reflect.Circle");

    //创建对象

    Circle circle = (Circle) clazz.newInstance();

    //获取指定参数的方法对象

    MethodMethod method = clazz.getMethod("draw",int.class,String.class);

    //通过Method对象的invoke(Object obj,Object... args)方法调用

    method.invoke(circle,15,"圈圈");

    //对私有无参方法的操作

    Method method1 = clazz.getDeclaredMethod("drawCircle");

    //修改私有方法的访问标识

    method1.setAccessible(true);

    method1.invoke(circle);

    //对有返回值得方法操作

    Method method2 =clazz.getDeclaredMethod("getAllCount");

    Integer count = (Integer) method2.invoke(circle);

    System.out.println("count:"+count);

    输出结果

    draw 圈圈,count=15

    drawCircle

    count:100

    在上述代码中调用方法,使用了Method类的invoke(Object obj,Object... args)第一个参数代表调用的对象,第二个参数传递的调用方法的参数。这样就完成了类方法的动态调用。

    三. 反射机制执行的流程

    -- 测试代码

    -- 执行流程图

    反射获取类实例

    首先调用了 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() 主要做了三件事:

    • 权限检测,如果不通过直接抛出异常;查找无参构造器,并将其缓存起来;调用具体方法的无参构造方法,生成实例并返回;

    下面是获取构造器的过程:

       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() 为获取匹配的构造方器;分三步:

    • 先获取所有的constructors, 然后通过进行参数类型比较;找到匹配后,通过 ReflectionFactory copy一份constructor返回;否则抛出 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(), 获取所有的构造器主要步骤;

    • 先尝试从缓存中获取;如果缓存没有,则从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
         * <p>
         * constructor is a "child" of the passed one; see the comments
         * <p>
         * 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);
    
        }

    返回构造器的实例后,可以根据外部进行进行类型转换,从而使用接口或方法进行调用实例功能了。

    反射获取方法

    • 第一步,先获取 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;
    
    }

    忽略第一个检查权限,剩下就只有两个动作了。

    • 获取所有方法列表;根据方法名称和方法列表,选出符合要求的方法;如果没有找到相应方法,抛出异常,否则返回对应方法;

    所以,先看一下怎样获取类声明的所有方法?

      // 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 / DelegatingMethodAccessorImplclass 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类加载器对象 ,这里每次都生成新的类加载器,是为了性能考虑,在某些情况下可以卸载这些生成的类,因为类的卸载是只有在类加载器可以被回收的情况下才会被回收的,如果用了原来的类加载器,那可能导致这些新创建的类一直无法被卸载。

    而反射生成的类,有时候可能用了就可以卸载了,所以使用其独立的类加载器,从而使得更容易控制反射类的生命周期。

    反射调用流程小结

    最后,用几句话总结反射的实现原理:

    反射类及反射方法的获取,都是通过从列表中搜寻查找匹配的方法,所以查找性能会随类的大小方法多少而变化;

    每个类都会有一个与之对应的Class实例,从而每个类都可以获取method反射方法,并作用到其他实例身上;

    反射也是考虑了线程安全的,放心使用;

    反射使用软引用relectionData缓存class信息,避免每次重新从jvm获取带来的开销;

    反射调用多次生成新代理Accessor, 而通过字节码生存的则考虑了卸载功能,所以会使用独立的类加载器;

    当找到需要的方法,都会copy一份出来,而不是使用原来的实例,从而保证数据隔离;

    调度反射方法,最终是由jvm执行invoke0()执行

    本文使用 文章同步助手 同步

    相关文章

      网友评论

          本文标题:java菜鸟到大佬——全网最全反射机制讲解

          本文链接:https://www.haomeiwen.com/subject/xlmdzrtx.html