594 字
3 分钟
HIT-软件构造 | Java 反射

在 Java 运行时,如果我们拿到一个 Object ,它可能是某个类的实例。如果我们想使用这个类的某个方法,却不知道这个类的名字,即连强制类型转换也做不了,那如何调用我们想要执行的方法呢。解决方案是使用 Java 反射。

Class 类与实例#

如果我们有两个类 Type1 和 Type2 的实例,然后将其转换成 Object 实例。表面上我们看不出这两个 Object 实例的区别,因为我们对他们的信息一无所知,但是这只是因为他们的引用是 Object 类型的而已。

Java runtime 提供了一种数据类型,称为 Class ,Java 程序开始运行后,每次首次加载一个 class ,都会用这个 class 的信息创建一个 Class 实例,即这个 Class 实例将会包含这个类的所有信息。Object 类提供了一个接口能让我们拿到任何一个对象的 Class 实例。也就是说,对于上述的 Type1 和 Type2 转换成 Object 后的实例,我们可以拿到它们的 Class 实例,来区分这两个实例哪一个是 Type1 的实例、哪一个是 Type2 。

class Type1 { ... }
class Type2 { ... }

Type1 type1 = new Type1();
Type2 type2 = new Type2();

Object obj1 = (Object)type1;
Object obj2 = (Object)type2;

Class cls1 = obj1.getClass();
Class cls2 = obj2.getClass();

除此之外,还可以已知类的名字,然后直接获得其 Class 实例:

Class cls = Type1.class;

或使用包路径格式的完整类名:

Class cls = Class.forName("com.vonbrank.Type1");

用 Class 实例访问字段#

假设有一个类 Person ,定义如下:

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

在下面的 test 方法中,我们只能拿到它实例的 Object 引用,如果想访问 name 可以这样写:

public class Main {
    public static void main(String[] args) {
        Person person = new Person("Xiao Ming");
        test(person);
    }

    static void test(Object obj) {
        Class cls = obj.getClass();
        Field field = cls.getDeclaredField("name");
        Object value = field.get(p);
        System.out.println(value); // "Xiao Ming"
    }

}

调用方法#

此处我们以 String 为例展示通过反射调用对象实例的方法:

public class Main {
    public static void main(String[] args) throws Exception {
        // String对象:
        String s = "Hello world";
        // 获取String substring(int)方法,参数为int:
        Method m = String.class.getMethod("substring", int.class);
        // 在s对象上调用该方法并获取结果:
        String r = (String) m.invoke(s, 6);
        // 打印调用结果:
        System.out.println(r);
    }
}
HIT-软件构造 | Java 反射
https://blog.vonbrank.com/posts/hit-software-construction-java-reflection/
作者
Von Brank
发布于
2022-05-21
许可协议
CC BY-NC-SA 4.0