Java反射

206 阅读2分钟
  • 反射就是指程序在运行期间可以拿到一个对象的所有信息。
  • 由于JVM为每个加载的class都创建了对应的Class实例,并在实例中保存了该class的所有信息,包括类名、包名、父类、实现的接口、所有方法、字段等,所以只要获取某个Class实例,我们就可以通过这个Class实例得到该实例对应的class的所有信息。

获取一个class的Class实例:

  1. 通过一个class的静态变量class获取
Class cls = String.class;
  1. 通过实例变量的getClass()方法获取
String str = "Hello";
Class cls = str.getClass();
  1. 通过静态方法Class.forName()获取
Class cls = Class.forName("java.lang.String");

因为Class实例在JVM中是唯一的,所以上述方法获取的Class实例是同一实例

Class cls1 = String.class;

String str = "Hello";
Class cls2 = str.getClass();

boolean isSameClass = (cls1 == cls2);//true

如果获取了一个Class实例,我们可以通过这个实例来创建对应类型的实例

Class cls = String.class;
String str = (String) cls.newInstance();//只能调用public的无参构造方法

动态加载

JVM在执行Java程序的时候,不是一次性把所有Class都加载到内存,而是第一次用到Class的时候才加载。

访问字段

  • Field getField(name): 根据字段名获取某个public的field(包括父类)
  • Field getDeclaredField(name): 获取当前类的field(不包括父类)(包括private)
  • Field[] getFields(): 所有field
  • Field[] getDeclaredFields(): 所有当前类field

一个Field对象包含了一个字段的所有信息:

  • getName(): 返回字段名称
  • getType(): 返回字段类型,他也是一个Class实例,例如 int.class
  • getModifiers(): 返回字段的修饰符,他是一个int值,不同的位表示不同含义(是否final,是否static,是否private等)

获取字段值:

  • 先获取Class实例,再获取Field实例,然后用Field.get(Object)获取指定实例的指定字段的值
  • 如果字段是private,则需要先Field.setAccessible(true),此方法可能会失败

设置字段值:

  • Field.set(Object, Object),第一个Object是指定的实例,第二个Object是待修改的值

调用方法

  • Method getMethod(name, Class...):(同获取字段)
  • Method getDeclaredMethod(name, Class...):
  • Method[] getMethods():
  • Method[] getDeclaredMethods():

一个Method对象包含一个方法的所有信息:

  • getName():
  • getReturnType():
  • getParameterTypes():
  • getModifiers():

使用方法:

  • Method.invoke(Object, args...): 第一个参数是对象实例,后面的参数要与方法参数一致
  • 使用静态方法时一个参数Object为null
  • 仍遵循多态,使用的是Object参数对应的方法

调用构造方法

  • Constructor getConstructor(Class...)
  • Constructor getDeclaredConstructor(Class...)
  • Constructor getConstructors()
  • Constructor getDeclaredConstructors()

总是当前类定义的构造方法,和父类无关,所以不存在多态问题

获取父类的Class

public class Main {
    public static void main(String[] args) throws Exception {
        Class i = Integer.class;
        Class n = i.getSuperclass();
        System.out.println(n);//Number
        Class o = n.getSuperclass();
        System.out.println(o);//Object
        System.out.println(o.getSuperclass());//null
        Class.getInterfaces();//返回类实现的接口,或者接口的父接口
    }
}

动态代理

在运行期动态创建某个interface的实例