跳转至

反射

一、反射机制提供的功能

  1. 在运行时判断任意一个对象所属的类
  2. 在运行时构造任意一个类的对象
  3. 在运行时判断任意一个类所具有的成员变量和方法
  4. 在运行时获取泛型信息
  5. 在运行时调用任意一个对象的成员变量和方法
  6. 在运行时处理注解
  7. 生成动态代理

二、反射相关的API

 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
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;

public class ReflectionTest {
    public static void main(String[] args) throws Exception {
        // 通过反射创建Person类的对象
        Class<Person> cls = Person.class;
        Constructor<Person> constructor = cls.getConstructor(String.class, int.class);
        Object obj = constructor.newInstance("Tom", 12);
        Person p = (Person) obj;
        System.out.println(p.toString());  // Person{name='Tom', age=12}

        // 通过反射调用对象指定的属性
        Field age = cls.getDeclaredField("age");
        age.set(p, 10);
        System.out.println(p.toString());  // Person{name='Tom', age=10}

        // 通过反射调用对象指定的方法
        Method show = cls.getDeclaredMethod("show");  // Hello
        show.invoke(p);

        // 通过反射调用Person的私有构造器
        Constructor<Person> constructor1 = cls.getDeclaredConstructor(String.class);
        constructor1.setAccessible(true);
        Person p1 = (Person) constructor1.newInstance("Jerry");
        System.out.println(p1);  // Process finished with exit code 0

        // 通过反射调用Person的私有属性
        Field name = cls.getDeclaredField("name");
        name.setAccessible(true);
        name.set(p1, "HanMeimei");
        System.out.println(p1);

        // 通过反射调用Person的私有方法
        Method showNation = cls.getDeclaredMethod("showNation", String.class);
        showNation.setAccessible(true);
        showNation.invoke(p1, "Chinese");  // Chinese


    }
}


class Person{
    private String name;
    public int age;

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

    public String getName() {
        return name;
    }

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

    public int getAge() {
        return age;
    }

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

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

    private Person(String name) {
        this.name = name;
    }

    public void show(){
        System.out.println("Hello");
    }

    private void showNation(String nation){
        System.out.println(nation);
    }
}

三、java.lang.Class

1. 类的加载过程

程序经过Javac命令以后,会生成一个或多个字节码文件(.class结尾),接着使用java命令对某个字节码文件进行解释运行。相对于将某个字节码文件加载到内存中,此过程就称为类的加载。加载到内存中的类就称为运行时类,此时的运行时类就作为Class的一个实例.

2. 获取Class实例的方式

加载到你内存中的运行时类,会缓存一定的时间,在此时间之内,可以通过不同的方式来获取此运行时类。

1. 调用运行时类的属性:.class

1
Class<Person> cls = Person.class;

2. 通过运行时类的对象

1
2
Person p = new Person();
Class cls = p.getClass();

3. 调用Class的静态方法

1
Class<?> cls = Class.forName("Person");

4. 使用类的加载器

1
2
ClassLoader classLoader = ReflectionTest.class.getClassLoader();
Class<?> cls = classLoader.loadClass("Person");

4. 哪些类型可以有Class对象

  1. 外部类,成员(成员内部类、静态内部类),局部内部类,匿名内部类
  2. 接口
  3. 数组
  4. 枚举
  5. 注解
  6. 基本数据类型
  7. void

5. 使用ClassLoader加载配置文件

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;

public class ClassLoaderTest {
    public static void main(String[] args) {
        Properties properties = new Properties();
        ClassLoader classLoader = ClassLoaderTest.class.getClassLoader();
        // 配置文件默认识别为当前module的src下
        InputStream resource = classLoader.getResourceAsStream("conf.properties");
        try {
            properties.load(resource);
        } catch (IOException e) {
            e.printStackTrace();
        }
        String user = properties.getProperty("user");
        System.out.println(user);

    }
}

四、创建运行时类的对象

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
public class newInstanceTest {
    public static void main(String[] args) throws IllegalAccessException, InstantiationException {
        Class<Person> cls = Person.class;
        /*
         * newInstance() 调用此方法,创建对应的运行时类的对象
         * 内部调用了运行时类的空参构造器
         * 要想此方法正常的创建运行时类的对象,要求:
         *   1. 运行时类必须提供空参的构造器
         *   2. 空参构造器的访问权限通常设置为public
         * 在JavaBean中要求提供一个public的空参构造器的原因:
         *   1. 便于通过反射,创建运行时类的对象
         *   2. 便于子类继承此运行类是,默认调用super()时,保证父类有此构造器
         * */
        Person p = cls.newInstance();
        System.out.println(p);  // Person@1b6d3586

    }
}

class Person {
}

五、获取运行时类的完整结构

  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
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
import java.io.Serializable;
import java.lang.annotation.Annotation;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.reflect.*;

import static java.lang.annotation.ElementType.*;
import static java.lang.annotation.ElementType.LOCAL_VARIABLE;

public class ReflectionTest {
    public static void main(String[] args) {
        Class<Person> cls = Person.class;
        // 1. 获取当前运行时类的所有属性结构
        // getFields(): 获取当前运行时类及其父类中声明为public访问权限的属性
        Field[] fields = cls.getFields();
        for (Field f : fields) {
            System.out.println(f);
        }
        System.out.println("================================");
        //      public int Person.id
        //      public double Creature.weight


        // getDeclaredFields(): 获取当前运行时类中声明的所有属性(不包含父类中声明的属性)
        Field[] declaredFields = cls.getDeclaredFields();
        for (Field f : declaredFields) {
            System.out.println(f);
        }
        //        public int Person.id
        //        private java.lang.String Person.name
        //        int Person.age
        System.out.println("================================");
        for (Field f : declaredFields) {
            // 获取修饰符
            int modifiers = f.getModifiers();
            System.out.println(Modifier.toString(modifiers));
        }
        System.out.println("================================");
        for (Field f : declaredFields) {
            // 获取数据类型
            Class<?> type = f.getType();
            System.out.println(type);
        }
        System.out.println("================================");
        for (Field f : declaredFields) {
            // 获取变量名
            String name = f.getName();
            System.out.println(name);
        }
        System.out.println("================================");


        // 2. 获取运行时类的方法结构
        // getMethods(): 获取当前运行时类及其父类中声明为public访问权限的方法
        Method[] methods = cls.getMethods();
        for (Method m : methods) {
            System.out.println(m);
        }
        System.out.println("================================");

        // getDeclaredMethods(): 获取当前运行时类中声明的所有方法(不包含父类中声明的属性)
        Method[] declaredMethods = cls.getDeclaredMethods();
        for (Method m : declaredMethods) {
            System.out.println(m);
        }
        System.out.println("================================");


        // 3. 获取方法的内部结构
        Method[] dMethods = cls.getDeclaredMethods();
        for (Method m : dMethods) {
            System.out.println("---------------------------");
            // 获取方法的注解
            Annotation[] annotations = m.getAnnotations();
            for (Annotation a : annotations) {
                System.out.println(a);
            }
            // 获取权限修饰符
            System.out.println(Modifier.toString(m.getModifiers()));
            // 获取返回值类型
            System.out.println(m.getReturnType().getName());
            // 获取方法名
            System.out.println(m.getName());
            // 获取形参
            Class<?>[] parameterTypes = m.getParameterTypes();
            if (!(parameterTypes == null && parameterTypes.length == 0)) {
                for (int i = 0; i < parameterTypes.length; i++) {
                    System.out.println(parameterTypes[i].getName());
                }
            }
        }

        // 4. 获取构造器结构
        System.out.println("================================");
        // getConstructors() 当前运行时类中声明为public的构造器
        Constructor<?>[] constructors = cls.getConstructors();
        for(Constructor c: constructors){
            System.out.println(c);
        }
        System.out.println("================================");
        Constructor<?>[] declaredConstructors = cls.getDeclaredConstructors();
        for(Constructor c: declaredConstructors){
            System.out.println(c);
        }
        System.out.println("================================");


        // 5. 获取运行类的父类及父类的泛型
        Class<? super Person> superclass = cls.getSuperclass();
        System.out.println(superclass);

        Type genericSuperclass = cls.getGenericSuperclass();
        System.out.println(genericSuperclass);
        ParameterizedType parameterizedType = (ParameterizedType) genericSuperclass;
        Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();
        // 获取带泛型的父类的泛型
        System.out.println(actualTypeArguments[0].getTypeName());
        System.out.println("================================");

        // 6. 获取运行时类的接口、所在包、注解
        Class<?>[] interfaces = cls.getInterfaces();
        for (Class i: interfaces){
            System.out.println(i);
        }
        System.out.println("---------------------------");

        Package aPackage = cls.getPackage();
        System.out.println(aPackage);
        System.out.println("---------------------------");

        Annotation[] annotations = cls.getAnnotations();
        for (Annotation a: annotations){
            System.out.println(a);
        }
    }

}

interface MyInterface {
    void info();
}

@Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE})
@Retention(RetentionPolicy.RUNTIME)
@interface MyAnnotation {
    String[] value() default "hello";
}


class Creature<T> implements Serializable {
    private char gender;
    public double weight;

    public void breath() {
        System.out.println("breath...");
    }

    private void eat() {
        System.out.println("eating");
    }
}

@MyAnnotation(value = "hi")
class Person extends Creature<String> implements Comparable<String>, MyInterface {
    public int id;
    private String name;

    int age;


    public Person() {

    }

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

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

    private void showNation(String nation) {
        System.out.println(nation);
    }

    @MyAnnotation
    public String display(String msg) {
        return msg;
    }

    @Override
    public void info() {
        System.out.println("info...");
    }

    @Override
    public int compareTo(String o) {
        return 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
 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
import java.io.Serializable;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.reflect.*;

import static java.lang.annotation.ElementType.*;
import static java.lang.annotation.ElementType.LOCAL_VARIABLE;

public class ReflectionTest {
    public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {
        Class<Person> cls = Person.class;
        // 创建运行时类的对象
        Person person = cls.newInstance();
        // 1. 操作运行时类中的属性
        // 获取指定的属性 要求属性是public的
        Field id = cls.getField("id");
        // 设置当前属性的值
        id.set(person, 1001);
        // 获取当前属性的值
        int pId = (int) id.get(person);
        System.out.println(pId);

        // 获取指定的属性
        Field name = cls.getDeclaredField("name");
        // 保证当前属性时可访问的
        name.setAccessible(true);
        // 设置指定对象的属性值
        name.set(person, "Tom");
        System.out.println(name.get(person));

        // 2. 操作运行时类中的方法
        // 获取指定的方法
        Method showNation = cls.getDeclaredMethod("showNation", String.class);
        showNation.setAccessible(true);
        // invoke()的返回值即为对应类中调用的方法的返回值
        Object o = showNation.invoke(person, "Chinese");
        System.out.println((String) o);


        // 3. 操作运行时类中的构造器
        Constructor<Person> declaredConstructor = cls.getDeclaredConstructor(String.class);
        declaredConstructor.setAccessible(true);
        Person jerry = declaredConstructor.newInstance("Jerry");
        System.out.println(jerry);
    }

}

interface MyInterface {
    void info();
}

@Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE})
@Retention(RetentionPolicy.RUNTIME)
@interface MyAnnotation {
    String[] value() default "hello";
}


class Creature<T> implements Serializable {
    private char gender;
    public double weight;

    public void breath() {
        System.out.println("breath...");
    }

    private void eat() {
        System.out.println("eating");
    }
}

@MyAnnotation(value = "hi")
class Person extends Creature<String> implements Comparable<String>, MyInterface {
    public int id;
    private String name;

    int age;


    public Person() {

    }

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

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

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

    private void showNation(String nation) {
        System.out.println(nation);
    }

    @MyAnnotation
    public String display(String msg) {
        return msg;
    }

    @Override
    public void info() {
        System.out.println("info...");
    }

    @Override
    public int compareTo(String o) {
        return 0;
    }
}