- 反射就是指程序在运行期间可以拿到一个对象的所有信息。
- 由于JVM为每个加载的class都创建了对应的Class实例,并在实例中保存了该class的所有信息,包括类名、包名、父类、实现的接口、所有方法、字段等,所以只要获取某个Class实例,我们就可以通过这个Class实例得到该实例对应的class的所有信息。
获取一个class的Class实例:
- 通过一个class的静态变量class获取
Class cls = String.class;
- 通过实例变量的getClass()方法获取
String str = "Hello";
Class cls = str.getClass();
- 通过静态方法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的实例