反射

2023/11/7 Java基础

# 1、反射

  • 每个类都有一个 Class 对象,包含了与类有关的信息。当编译一个新类时,会产生一个同名的 .class 文件,该文件内容保存着 Class 对象。
  • 类加载相当于 Class 对象的加载,类在第一次使用时才动态加载到 JVM 中。也可以使用 Class.forName("com.mysql.jdbc.Driver")这种方式来控制类的加载,该方法会返回一个 Class 对象。
  • 反射可以提供运行时的类信息,并且这个类可以在运行时才加载进来,甚至在编译时期该类的 .class 不存在也可以加载进来。

Class 和 java.lang.reflect 一起对反射提供了支持,java.lang.reflect 类库主要包含了以下三个类:

  • Field:可以使用 get() 和 set() 方法读取和修改 Field 对象关联的字段;
  • Method:可以使用 invoke() 方法调用与 Method 对象关联的方法;
  • Constructor:可以用 Constructor 的 newInstance() 创建新的对象。

反射就是把java类中的各种成分映射成一个个的Java对象。已知类的包名路径情况下,可以通过反射操作类,用于获取字段、调用方法、创建对象等。

# 2、反射的优点

  • 可扩展性

应用程序可以利用全限定名创建可扩展对象的实例,来使用来自外部的用户自定义类。

  • 类浏览器和可视化开发环境

一个类浏览器需要可以枚举类的成员。可视化开发环境(如 IDE)可以从利用反射中可用的类型信息中受益,以帮助程序员编写正确的代码。

  • 调试器和测试工具

调试器需要能够检查一个类里的私有成员。测试工具可以利用反射来自动地调用类里定义的可被发现的 API 定义,以确保一组测试中有较高的代码覆盖率。

# 3、反射的缺点

尽管反射非常强大,但也不能滥用。如果一个功能可以不用反射完成,那么最好就不用。在我们使用反射技术时,下面几条内容应该牢记于心。

  • 性能开销

反射涉及了动态类型的解析,所以 JVM 无法对这些代码进行优化。因此,反射操作的效率要比那些非反射操作低得多。我们应该避免在经常被执行的代码或对性能要求很高的程序中使用反射。

  • 安全限制

使用反射技术要求程序必须在一个没有安全限制的环境中运行。如果一个程序必须在有安全限制的环境中运行,如 Applet,那么这就是个问题了。

  • 内部暴露

由于反射允许代码执行一些在正常情况下不被允许的操作(比如访问私有的属性和方法),所以使用反射可能会导致意料之外的副作用,这可能导致代码功能失调并破坏可移植性。反射代码破坏了抽象性,因此当平台发生改变的时候,代码的行为就有可能也随着变化。

参考:Trail: The Reflection API (opens new window)

# 4、应用场景

  • Spring/Spring Boot、MyBatis 等等框架中都大量使用了反射机制。这些框架运用了大量的动态代理,而动态代理的实现也是依赖于反射。
  • Java中的注解也是用到了反射。

JDK 实现动态代理的示例代码

public class DebugInvocationHandler implements InvocationHandler {
    /**
     * 代理类中的真实对象
     */
    private final Object target;

    public DebugInvocationHandler(Object target) {
        this.target = target;
    }

    public Object invoke(Object proxy, Method method, Object[] args) throws InvocationTargetException, IllegalAccessException {
        System.out.println("before method " + method.getName());
        Object result = method.invoke(target, args);
        System.out.println("after method " + method.getName());
        return result;
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

注解的获取,就是基于反射分析类,然后获取到类/属性/方法/方法的参数上的注解。

# 5、反射详解

# 5.1、反射基础概念

反射机制,它允许我们在运行时发现和使用类的信息。

一个类包含如成员变量、方法、构造方法、包等各种元素,通过使用反射技术,我们能够对这个类进行深度分析,并把各种组成部分转化为单独的对象。

# 5.2、Class类

  • Class类是一个真实存在的类,需要和class区分开,Class类存在于JDK的java.lang包中。
  • Class类的实例表示java应用运行时的类(class ans enum)或接口(interface and annotation)。
  • 每个java类运行时都在JVM里表现为一个class对象,可通过类名.class、类型.getClass()、Class.forName("类名")等方法获取class对象。
  • 数组同样也被映射为class 对象的一个类,所有具有相同元素类型和维数的数组都共享该 Class 对象。
  • 基本类型boolean,byte,char,short,int,long,float,double和关键字void同样表现为 class 对象。
public final class Class<T> implements java.io.Serializable,
                              GenericDeclaration,
                              Type,
                              AnnotatedElement {
    private static final int ANNOTATION= 0x00002000;
    private static final int ENUM      = 0x00004000;
    private static final int SYNTHETIC = 0x00001000;

    private static native void registerNatives();
    static {
        registerNatives();
    }

    private Class(ClassLoader loader) {
        // Initialize final field for classLoader.  The initialization value of non-null
        // prevents future JIT optimizations from assuming this final field is null.
        classLoader = loader;
    }

    ... ...
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

总结Class类

  • Class类与class关键字:在Java中,Class是一个特殊的类,它的主要作用是在运行时存储和提供其他类的元数据信息。而class则是Java语言中的一个关键字,用于定义一个新的类。
  • Class对象:当你创建一个新的类并编译后,JVM为此类生成一个Class对象。这个对象包含了该类的全部类型信息,并会保存在和这个类同名的.class字节码文件中。
  • Class对象的唯一性:每个使用class关键字定义的类,在内存中都有一个与之对应的唯一的Class对象,用于描述其元数据信息。无论你创建了多少个该类的实例对象,他们的元数据信息都是基于这同一个Class对象。
  • Class类的构造函数:Class类的构造函数是私有的,这就意味着开发人员无法直接实例化Class类。Class对象的创建和加载只能由JVM完成。
  • Class类与反射技术:反射技术就是基于Class对象,能够在运行时动态获取和修改类的元数据信息,比如获取类的成员函数、成员变量、构造函数等信息,甚至可以动态调用对象的方法、修改成员变量的值等。

# 5.3、类加载

类加载机制是Java语言实现面向对象编程的重要机制之一,同时也是保证Java程序安全和可靠的重要手段。

类加载机制

类加载案例

类加载机制的详细流程

  • 加载

在加载阶段,JVM会根据类的全限定名找到对应的二进制字节码文件,然后将其加载到内存中。加载过程可以分为以下几个步骤:

  • 通过类的全限定名来定位字节码文件的位置,可以从文件系统、网络等地方加载字节码文件。
  • 读取字节码文件的内容,并将其转换成内存中的数据结构,如Method Area中的Class对象。
  • 创建一个Class对象,该对象包含了该类的一些元信息,如类的全限定名、父类、实现的接口等。
  • 验证

在验证阶段,JVM会对加载到内存中的字节码进行校验,以确保字节码文件的结构是符合Java虚拟机规范的,不会包含任何不安全或破坏性的内容。验证过程包括以下几个步骤:

  • 文件格式验证:检查字节码文件是否符合Java虚拟机规范的格式要求。
  • 元数据验证:检查字节码文件中的符号引用是否能正确解析并且符合语义要求。
  • 字节码验证:对字节码文件进行静态分析,检查是否有不安全或破坏性的行为。
  • 准备

在准备阶段,JVM会为类的静态变量分配内存,并设置默认初始值。静态变量存储在Method Area中的静态变量区。准备阶段不会执行任何Java代码。

  • 解析

在解析阶段,JVM会将字节码文件中的符号引用替换为直接引用,以确保能正确访问其他类、方法和字段。解析过程分为以下两个步骤:

  • 类或接口的解析:将类或接口的符号引用解析为直接引用,即找到所引用的类或接口在内存中的位置。
  • 字段、方法和方法调用的解析:将字段、方法和方法调用的符号引用解析为直接引用,即找到所引用的字段的内存位置或方法的内存位置。
  • 初始化

在初始化阶段,JVM会执行类的静态初始化代码,包括为静态变量赋初始值和执行静态代码块。初始化过程是类加载的重要阶段,也是类与程序其他部分交互的重要环节。

  • 使用

在使用阶段,JVM会根据需要使用被加载的类。使用阶段包括以下几个方面:

  • 调用类的静态方法或访问类的静态变量。
  • 创建类的实例对象。
  • 调用类的实例方法。
  • 卸载

不是所有的类都能卸载,只有满足以下条件的类才会被卸载:

  • 该类的所有实例都被GC判定为不可达。
  • 该类的类加载器被GC判定为不可达。
  • 该类的Class对象被GC判定为不可达。

更多参考:JVM 类加载机制

# 5.4、反射的使用

基于反射可以获取Class类以及类中的成员变量、方法、构造方法等。

在Java中,Class类与java.lang.reflect类库一起对反射技术进行了全力的支持。

反射包中常用的类

  • Class类:提供或获得某个对象的类型信息,上面有详解过了。
  • Constructor类:表示的是Class 对象所表示的类的构造方法,利用它可以在运行时动态创建对象。
  • Field类:表示Class对象所表示的类的成员变量,通过它可以在运行时动态修改成员变量的属性值(包含private)。
  • Method类:表示Class对象所表示的类的成员方法,通过它可以动态调用对象的方法(包含private)。

# Class类对象的获取

  • 获取class对象的v方式

  • 根据类名:类名.class
  • 根据对象:对象.getClass()
  • 根据全限定类名:Class.forName(全限定类名)
  • 案例
public class User {
    private String name = "init";
    private int age;

    public User() {}

    public User(String name, int age) {
        super();
        this.name = name;
        this.age = age;
    }

    private String getName() {
        return name;
    }
    private void setName(String name) {
        this.name = name;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "User [name=" + name + ", age=" + age + "]";
    }
}

@Test
public void classTest() throws Exception {
    // 获取Class对象的三种方式
    logger.info("根据类名:  \t" + User.class);
    logger.info("根据对象:  \t" + new User().getClass());
    logger.info("根据全限定类名:\t" + Class.forName("com.test.User"));
    // 常用的方法
    logger.info("获取全限定类名:\t" + userClass.getName());
    logger.info("获取类名:\t" + userClass.getSimpleName());
    logger.info("实例化:\t" + userClass.newInstance());
}


/** 输出如下
根据类名:  	class com.test.User
根据对象:  	class com.test.User
根据全限定类名:	class com.test.User
获取全限定类名:	com.test.User
获取类名:	User
实例化:	User [name=init, age=0]
**/
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
  • Class类的常用方法
方法名 描述
forName(String className) 1. 获取Class对象的一个引用,但引用的类还没有加载
(该类的第一个对象没有生成)就加载了这个类。

2. 为了产生Class引用,forName()立即就进行了初始化。
getName() 获取类的名字,包括包名。
getSimpleName() 获取类的简单名字,不包括包名。
getPackage() 获取类所在的包。
getSuperclass() 获取类的父类。
getInterfaces() 获取类实现的接口。
getDeclaredFields() 获取类声明的所有字段。
getField(String name) 获取指定名称的公共字段。
getDeclaredMethods() 获取类声明的所有方法。
getMethod(String name, Class<?>... parameterTypes) 获取指定名称和参数类型的公共方法。
getDeclaredConstructors() 获取类声明的所有构造方法。
getConstructor(Class<?>... parameterTypes) 获取指定参数类型的公共构造方法。
newInstance() 创建类的实例。
isAssignableFrom(Class<?> cls) 判断当前类是否是指定类的父类或接口。
isInstance(Object obj) 判断指定对象是否是当前类的实例。
  • 注意一下getName、getCanonicalName与getSimpleName的区别
package com.bt;
public class Test {
    private  class inner{}

    public static void main(String[] args) throws ClassNotFoundException {
        //普通类
        System.out.println(Test.class.getSimpleName()); //Test
        System.out.println(Test.class.getName()); //com.cry.Test
        System.out.println(Test.class.getCanonicalName()); //com.cry.Test
        //内部类
        System.out.println(inner.class.getSimpleName()); //inner
        System.out.println(inner.class.getName()); //com.cry.Test$inner
        System.out.println(inner.class.getCanonicalName()); //com.cry.Test.inner
        //数组
        System.out.println(args.getClass().getSimpleName()); //String[]
        System.out.println(args.getClass().getName()); //[Ljava.lang.String;
        System.out.println(args.getClass().getCanonicalName()); //java.lang.String[]
        //我们不能用getCanonicalName去加载类对象,必须用getName
        //Class.forName(inner.class.getCanonicalName()); 报错
        Class.forName(inner.class.getName());
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

# Constructor类及其用法

Constructor类存在于反射包(java.lang.reflect)中,用于表示类的构造方法。Constructor类提供了一些方法来操作构造方法的信息和行为。

Constructor类常用方法

  • getName():返回构造方法的名称。
  • getModifiers():返回构造方法的修饰符,使用Modifier类判断修饰符的具体含义。
  • getParameterTypes():返回构造方法的参数类型数组。
  • getParameterCount():返回构造方法的参数个数。
  • getExceptionTypes():返回构造方法声明的异常类型数组。
  • newInstance(Object... initargs):通过构造方法创建类的对象实例。

案例

class User {
    private int age;
    private String name;
    public User() {
        super();
    }
    public User(String name) {
        super();
        this.name = name;
    }

    /**
     * 私有构造
     * @param age
     * @param name
     */
    private User(int age, String name) {
        super();
        this.age = age;
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return "User{" +
                "age=" + age +
                ", name='" + name + '\'' +
                '}';
    }
}

public class ConstructionTest implements Serializable {
    public static void main(String[] args) throws Exception {

        Class<?> clazz = null;

        //获取Class对象的引用
        clazz = Class.forName("com.example.javabase.User");

        //第一种方法,实例化默认构造方法,User必须无参构造函数,否则将抛异常
        User user = (User) clazz.newInstance();
        user.setAge(20);
        user.setName("Jack");
        System.out.println(user);

        System.out.println("--------------------------------------------");

        //获取带String参数的public构造函数
        Constructor cs1 =clazz.getConstructor(String.class);
        //创建User
        User user1= (User) cs1.newInstance("hiway");
        user1.setAge(22);
        System.out.println("user1:"+user1.toString());

        System.out.println("--------------------------------------------");

        //取得指定带int和String参数构造函数,该方法是私有构造private
        Constructor cs2=clazz.getDeclaredConstructor(int.class,String.class);
        //由于是private必须设置可访问
        cs2.setAccessible(true);
        //创建user对象
        User user2= (User) cs2.newInstance(25,"hiway2");
        System.out.println("user2:"+user2.toString());

        System.out.println("--------------------------------------------");

        //获取所有构造包含private
        Constructor<?> cons[] = clazz.getDeclaredConstructors();
        // 查看每个构造方法需要的参数
        for (int i = 0; i < cons.length; i++) {
            //获取构造函数参数类型
            Class<?> clazzs[] = cons[i].getParameterTypes();
            System.out.println("构造函数["+i+"]:"+cons[i].toString() );
            System.out.print("参数类型["+i+"]:(");
            for (int j = 0; j < clazzs.length; j++) {
                if (j == clazzs.length - 1)
                    System.out.print(clazzs[j].getName());
                else
                    System.out.print(clazzs[j].getName() + ",");
            }
            System.out.println(")");
        }
    }
}


/** 输出结果
User{age=20, name='Jack'}
--------------------------------------------
user1:User{age=22, name='hiway'}
--------------------------------------------
user2:User{age=25, name='hiway2'}
--------------------------------------------
构造函数[0]:private com.example.javabase.User(int,java.lang.String)
参数类型[0]:(int,java.lang.String)
构造函数[1]:public com.example.javabase.User(java.lang.String)
参数类型[1]:(java.lang.String)
构造函数[2]:public com.example.javabase.User()
参数类型[2]:()
*/
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116

更多方法可查看JDK官方文档

# Field类及其用法

Field类存在于反射包(java.lang.reflect)中,用于表示类的字段(成员变量)。Field类提供了一些方法来操作字段的信息和行为。

Field类常用方法

  • getName():返回字段的名称。
  • getType():返回字段的类型。
  • getModifiers():返回字段的修饰符,使用Modifier类判断修饰符的具体含义。
  • get(Object obj):获取给定对象上该字段的值。
  • set(Object obj, Object value):设置给定对象上该字段的值为指定的值。
  • isAccessible():判断字段是否可访问。
  • setAccessible(boolean flag):设置字段的可访问性。
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;

public class MyClass {
    private String name;
    public int age;
    
    public static void main(String[] args) {
        MyClass obj = new MyClass();
        
        Class<?> clazz = obj.getClass();
        
        try {
            // 获取类的所有字段
            Field[] fields = clazz.getDeclaredFields();
            
            // 遍历字段
            for (Field field : fields) {
                System.out.println("Field name: " + field.getName());
                System.out.println("Field type: " + field.getType().getName());
                System.out.println("Field modifiers: " + Modifier.toString(field.getModifiers()));
                
                // 设置字段可访问
                field.setAccessible(true);
                
                // 获取字段的值
                Object value = field.get(obj);
                System.out.println("Field value: " + value);
                
                // 修改字段的值
                if (field.getType() == int.class) {
                    field.setInt(obj, 30);
                } else if (field.getType() == String.class) {
                    field.set(obj, "John");
                }
                
                System.out.println("New field value: " + field.get(obj));
                System.out.println();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
  • 如果我们不期望获取其父类的字段,则需使用Class类的getDeclaredField/getDeclaredFields方法来获取字段即可,倘若需要连带获取到父类的字段,那么请使用Class类的getField/getFields,但是也只能获取到public修饰的的字段,无法获取父类的私有字段。
  • set(Object obj, Object value)方法是Field类本身的方法,用于设置字段的值,而get(Object obj)则是获取字段的值。
  • Field类还提供了专门针对基本数据类型的方法,如setInt()/getInt()、setBoolean()/getBoolean、setChar()/getChar()等等方法。
//获取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
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

# Method类及其用法

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

Method类常用方法

  • getName():获取方法的名称
  • getReturnType():获取方法的返回类型,返回一个Class对象。
  • getParameterTypes():获取方法的参数类型,返回一个Class数组。
  • getModifiers():获取方法的修饰符,返回一个整数值。可以通过Modifier类的方法来解析修饰符值。
  • invoke(Object obj, Object... args):通过反射调用方法,传递对应的实例对象和参数。
  • setAccessible(boolean flag):设置方法的访问权限,如果为true,则可以访问私有方法。需要注意的是,调用私有方法前必须调用该方法设置为可访问。
import java.lang.reflect.Field;

public class Person {
    private String name;
    public int age;

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public static void main(String[] args) {
        Person person = new Person("John", 30);

        // 获取Person类的age字段
        try {
            Field field = Person.class.getDeclaredField("age");

            // 设置字段可访问(因为age是public,所以不需要设置可访问性)
            field.setAccessible(true);

            // 获取字段的值
            int ageValue = field.getInt(person);
            System.out.println("Original age: " + ageValue);

            // 修改字段的值
            field.setInt(person, 40);
            System.out.println("New age: " + field.getInt(person));
        } catch (NoSuchFieldException | IllegalAccessException e) {
            e.printStackTrace();
        }
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33

# 6、深入理解反射机制

# 6.1、案例

  • 反射是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);
    }
}

/** 输出结果
hello,call directly
hello,method invoke
*/
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32

通过以上案例我们可以很容易的通过反射来进行动态加载类,并且调用其中的方法。接下来我们分析反射的执行流程,涉及源码。

# 6.2、反射获取类实例解析

  • 首先调用了 java.lang.Class 的静态方法,获取类信息!
/**
 * java.lang.Class
 * Class.forName("类全路径")
 */
@CallerSensitive
public static Class<?> forName(String className)
            throws ClassNotFoundException {
    // 先通过反射,获取调用进来的类信息,从而获取当前的 classLoader(获取类的Class对象)
    Class<?> caller = Reflection.getCallerClass();
    // 调用native方法进行获取class信息
    return forName0(className, true, ClassLoader.getClassLoader(caller), caller);
}

/**
 * sun.reflect.Reflection
 * Reflection.getCallerClass(),调用了Reflection类中的native方法,获取 classLoader
 */
@CallerSensitive
public static native Class<?> getCallerClass();

/**
 * java.lang.Class
 * 调用native方法进行获取class信息,接受类名、初始化标志(是否初始化)、类加载器和调用者类作为参数
 */
private static native Class<?> forName0(String name, boolean initialize,
                                            ClassLoader loader,
                                            Class<?> caller)
        throws ClassNotFoundException;

/**
 * java.lang.ClassLoader
 * 获取类加载器
 */
static ClassLoader getClassLoader(Class<?> caller) {
        // This can be null if the VM is requesting it
        if (caller == null) {
            return null;
        }
        // Circumvent security check since this is package-private
        return caller.getClassLoader0();
    }

/**
 * java.lang.Class
 * 返回类加载器
 */
ClassLoader getClassLoader0() { return classLoader; }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47

  • forName()反射获取类信息,并没有将实现留给了java,而是交给了jvm去加载。
  • 主要是先获取 ClassLoader, 然后调用 native 方法,获取信息,加载类则是回调 java.lang.ClassLoader。

在这个过程中,我们调用native方法给到JVM操作,并将ClassLoader也传过去了,jvm又会回调 ClassLoader 进类加载。

// java.lang.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);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
  • 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;
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62

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));
}
1
2
3
4
5
6
7
8
9
10
11
12
13

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;
        }
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72

如上,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;
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

其中,还有一个点,就是如何比较构造是否是要查找构造器,其实就是比较类型完成相等就完了,有一个不相等则返回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;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53

通过上面,获取到 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);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54

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

# 6.3、反射获取方法解析

  • 第一步,先获取 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
4
5
6
7
8
9
10
11

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

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

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

// 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;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

很相似,和获取所有构造器的方法很相似,都是先从缓存中获取方法,如果没有,则从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;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
  • 第二步,根据方法名和参数类型过滤指定方法返回:
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));
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

大概意思看得明白,就是匹配到方法名,然后参数类型匹配,才可以。

  • 但是可以看到,匹配到一个方法,并没有退出for循环,而是继续进行匹配。
  • 这里是匹配最精确的子类进行返回(最优匹配)
  • 最后,还是通过 ReflectionFactory, copy 方法后返回。

# 6.4、调用 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);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

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;
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38

两个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;
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55

进行 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);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

其中, 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);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

generate() 戳详情。

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();

    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);
                    }
                }
            });
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161

咱们主要看这一句:ClassDefiner.defineClass(xx, declaringClass.getClassLoader()).newInstance();

在ClassDefiner.defineClass方法实现中,每被调用一次都会生成一个DelegatingClassLoader类加载器对象 ,这里每次都生成新的类加载器,是为了性能考虑,在某些情况下可以卸载这些生成的类,因为类的卸载是只有在类加载器可以被回收的情况下才会被回收的,如果用了原来的类加载器,那可能导致这些新创建的类一直无法被卸载。

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

# 6.5、反射调用流程小结

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

  • 反射类及反射方法的获取,都是通过从列表中搜寻查找匹配的方法,所以查找性能会随类的大小方法多少而变化;
  • 每个类都会有一个与之对应的Class实例,从而每个类都可以获取method反射方法,并作用到其他实例身上;
  • 反射也是考虑了线程安全的,放心使用;
  • 反射使用软引用relectionData缓存class信息,避免每次重新从jvm获取带来的开销;
  • 反射调用多次生成新代理Accessor, 而通过字节码生存的则考虑了卸载功能,所以会使用独立的类加载器;
  • 当找到需要的方法,都会copy一份出来,而不是使用原来的实例,从而保证数据隔离;
  • 调度反射方法,最终是由jvm执行invoke0()执行;

参考:深入理解java反射原理 (opens new window)