Java反射

基于黑马课程重新写了一份反射的笔记

反射

概述

可以用反射来获取类中的所有信息

获取class对象的三种方式

Class.forName(“全类名”)

全类名:包名 + 类名

1
2
3
4
5
6
try {
    Class clazz = Class.forName("com.yuanyu.Student");
    System.out.println(clazz);// class com.yuanyu.Student
} catch (ClassNotFoundException e) {
    throw new RuntimeException(e);
}

在idea中,全类名可以直接复制

image-20250802215955065

类名.class

1
System.out.println(Student.class);// class com.yuanyu.Student

对象.getClass()

1
2
Student student = new Student();
System.out.println(student.getClass());// class com.yuanyu.Student

以上三种方式获取的字节码文件对象是一样的

获取构造方法

获取构造方法

Class类中用于获取构造方法的方法

Constructor<?>[] getConstructors():返回所有公共构造方法对象的数组

Constructor<?>[] getDeclaredConstructors():返回所有构造方法对象的数组

Constructor<T> getConstructor(Class<?>... parameterTypes):返回单个公共构造方法对象

Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes):返回单个构造方法对象

 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
try {
    // 1. 获取class字节码文件对象
    Class clazz = Class.forName("com.yuanyu.Student");
    // 2. 获取构造方法
    // 2.1 获取所有public修饰的构造方法
    Constructor[] constructors1 = clazz.getConstructors();
    for (Constructor constructor : constructors1) {
        System.out.println(constructor);
    }
    System.out.println("============================================");
    // 2.2 获取所有构造方法(包括:private、protected等)
    Constructor[] constructors2 = clazz.getDeclaredConstructors();
    for (Constructor constructor : constructors2) {
        System.out.println(constructor);
    }
    System.out.println("============================================");
    // 2.3 获取指定参数类型的public构造方法
    Constructor constructor1 = clazz.getConstructor(String.class, int.class);
    System.out.println(constructor1);
    // Constructor constructor2 = clazz.getConstructor(int.class);
    // System.out.println(constructor2);// 会报错
    Constructor constructor3 = clazz.getConstructor();
    System.out.println(constructor3);
    System.out.println("============================================");
    // 2.4 获取指定参数类型的构造方法(包括:private、protected等)
    Constructor declaredConstructor = clazz.getDeclaredConstructor(int.class);
    System.out.println(declaredConstructor);
} catch (Exception e) {
    e.printStackTrace();
}

输出结果:

image-20250802223903969

其中,我的Student类如下

 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
package com.yuanyu;

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

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

    public Student() {

    }

    protected Student(String name) {
        this.name = name;
    }

    private Student(int age) {
        this.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;
    }

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

用途

获取构造方法的权限修饰符、参数列表等,具体不多赘述

 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
try {
    Class clazz = Class.forName("com.yuanyu.Student");
    Constructor declaredConstructor = clazz.getDeclaredConstructor(String.class, int.class);
    // 获取权限修饰符
    int modifiers = declaredConstructor.getModifiers();
    System.out.println(modifiers);// 1(表示获取的这个构造是public的,具体数字表示什么,可以上网查阅)
    
    // 获取参数列表
    Parameter[] parameters = declaredConstructor.getParameters();
    for (Parameter parameter : parameters) {
        System.out.println(parameter);
        /**
         * 输出:
         * java.lang.String name
         * int age
         */
    }
    
    // 暴力反射:临时修改访问权限,使得私有的构造方法可以被访问
    // 如果是私有的构造方法,可以临时修改访问权限,使得私有的构造方法可以被访问
    declaredConstructor.setAccessible(true);
    Student student = (Student) declaredConstructor.newInstance("张三", 18);
    System.out.println(student);// Student{name='张三', age=18}	(如果输出的是com.yuanyu.Student@5a14e60d这种,说明没有重写toString方法)
} catch (Exception e) {
    e.printStackTrace();
}

获取成员变量

获取成员变量

Class类中用于获取成员变量的方法

Field [] getFields ():返回所有公共成员变量对象的数组 Field [] getDeclaredFields ():返回所有成员变量对象的数组 Field getField (String name):返回单个公共成员变量对象 Field getDeclaredField (String 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
try {
    Class clazz = Class.forName("com.yuanyu.Student");
    // 获取name字段
    Field field = clazz.getDeclaredField("name");
    System.out.println(field);// private java.lang.String com.yuanyu.Student.name

    // 获取权限修饰符
    int modifiers = field.getModifiers();
    System.out.println(modifiers);// 2(表示获取的这个字段是private的,具体数字表示什么,可以上网查阅)

    // 获取成员变量名
    String name = field.getName();
    System.out.println(name);// name

    // 获取数据类型
    Class<?> type = field.getType();
    System.out.println(type);// class java.lang.String

    // 获取成员变量记录的值
    Student student = new Student("张三", 18);
    field.setAccessible(true);
    Object o = field.get(student);
    System.out.println(o);// 张三

    // 修改对象中记录的值
    field.set(student, "李四");
    System.out.println(student);// Student{name='李四', age=18}
} catch (Exception e) {
    e.printStackTrace();
}

获取成员方法

获取成员方法

Method [] getMethods ():返回所有公共成员方法对象的数组,包括继承的 Method [] getDeclaredMethods ():返回所有成员方法对象的数组,不包括继承的 Method getMethod (String name, Class... parameterTypes):返回单个公共成员方法对象

Method getDeclaredMethod(String name, Class... parameterTypes):返回单个成员方法对象

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
try {
    // 获取class字节码文件对象
    Class clazz = Class.forName("com.yuanyu.Student");
    // 获取指定的单一方法
    // 后面的参数可以区分不同的同名方法
    Method eat1 = clazz.getDeclaredMethod("eat", String.class, int.class);
    System.out.println(eat1);// private void com.yuanyu.Student.eat(java.lang.String, int)
    Method eat2 = clazz.getDeclaredMethod("eat", String.class);
    System.out.println(eat2);// private void com.yuanyu.Student.eat(java.lang.String)
} catch (Exception e) {
    e.printStackTrace();
}

为了演示,在Student类中加入了下面三个方法

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
public String sleep() {
    System.out.println("睡觉中~~~");
    return "别打扰";
}

private void eat(String food) throws IOException, InterruptedException, NullPointerException {
    System.out.println("我要吃" + food);
}

private void eat(String food, int num) {
    System.out.println("我要吃" + num + "个" + food);
}

用途

获取方法的修饰符、名字、形参、返回值、抛出的异常等,具体不多赘述

 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
try {
    // 获取class字节码文件对象
    Class clazz = Class.forName("com.yuanyu.Student");
    // 获取指定的单一方法
    Method method = clazz.getDeclaredMethod("eat", String.class);

    // 获取权限修饰符
    int modifiers = method.getModifiers();
    System.out.println(modifiers);// 2(表示获取的这个方法时private的,具体数字表示什么,可以上网查阅)

    // 获取方法名
    String name = method.getName();
    System.out.println(name);// eat

    // 获取形参
    Parameter[] parameters = method.getParameters();
    for (Parameter parameter : parameters) {
        System.out.println(parameter);// java.lang.String food
    }

    // 获取方法抛出的异常
    Class<?>[] exceptionTypes = method.getExceptionTypes();
    for (Class<?> exceptionType : exceptionTypes) {
        System.out.println(exceptionType);
        /**
         * 输出:
         * class java.io.IOException
         * class java.lang.InterruptedException
         * class java.lang.NullPointerException
         */
    }

    /** 方法运行
     * Method类中用于创建对象的方法
     * Object invoke(Object obj, Object... args):运行方法
     * 参数一:调用方法的对象
     * 参数二:调用方法时,需要传入的参数(如果没有就不写)
     * 返回值:被调用方法返回的值(如果没有就不写)
     */
    Student student = new Student();
    method.setAccessible(true);
    method.invoke(student, "肯德基");// 我要吃肯德基

    // 方法有返回值时,可以获取返回值
    Object result = clazz.getDeclaredMethod("sleep").invoke(student);// 睡觉中~~~
    System.out.println(result);// 别打扰
} catch (Exception e) {
    e.printStackTrace();
}

上述笔记基于黑马课程

本站于2025年3月26日建立
使用 Hugo 构建
主题 StackJimmy 设计