Java反射的概念


反射(Reflection),是指程序在运行期可以拿到一个对象的所有信息。

在程序中,如果我们要调用对象的方法或者是访问对象的字段,一般是使用对象的实例。

User user = new User();
user.getName();

那如果只有Object实例,怎么调用Person的方法?有一种方法是强转。

Object obj = new Object();
User user1 = (User) obj;

但是在使用强转的方法中,还是需要importUser类,否则编译还是无法通过。

因此在Java语言中,使用反射来解决在运行期,对某个实例一无所知的情况下,如何调用其方法。

反射

Java的数据类型分为基本数据类型和引用数据类型,所有的引用数据类型都是class。class(包括interface)的本质都是数据类型(Type)。

class是由JVM在执行过程中动态加载的。JVM在第一次读取到一种class类型时,将其加载进内存。

每加载一种class,JVM就为其将创建一个Class类型的实例。其中,Class类型是一个名叫Classclass,其定义如下:

public final class Class implements java.io.Serializable,
                              GenericDeclaration,
                              Type,
                              AnnotatedElement {
    /*
     * Private constructor. Only the Java Virtual Machine creates Class objects.
     * This constructor is not used and prevents the default constructor being
     * generated.
     */
    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;
    }

    ...

}

当JVM要加载User类时,首先读取User.class文件,然后为User类创建一个Class实例。

如果我们自己要

Class cls = new Class(User.class);

这里有一点要注意,由上面Class类型的定义可以看到,构造器是私有的,因此只能是在JVM内部创建,我们的Java程序无法像这样创建Class实例。

在JVM中,持有的每个Class实例都指向一个引用数据类型。一个Class实例包含了对应class的所有完整信息,包括类名、包名、父类、实现的接口、所有方法、字段等。所以只要有了Class实例,我们就可以通过Class获取到对应的Class的所有信息。

通过Class实例获取信息示例:

Class cls = User.class;

System.out.println(cls.getName());
System.out.println(cls.getPackage());
System.out.println(cls.getSuperclass());

// 获取所有public的field(包括父类)
Field[] fields = cls.getDeclaredFields();
for (int i = 0; i < fields.length; i++) {
    System.out.println(fields[i]);
}

// 获取当前类的field(不包括父类)
Field[] fields2 = cls.getFields();
for (int i = 0; i < fields2.length; i++) {
    System.out.println(fields2[i]);
}