-------------------------------- Java 反射 -------------------------------
1 理解类的加载过程
任何一个类编译后生成一个.class 文件,JVM 的类加载器将此.class 文件加载到内
存中。.class 文件就对应有一个 java.lang.Class 类的实例。
可以理解为,加载的类本身就作为 Class 类的实例
涉及到的包 / 类: ① java.lang.Class 可以看做反射的根源
②java.lang.refect
2 如何实例化 Class 类
//1.直接调用类的属性.class
Class clazz = Person.class;
clazz = Animal.class;
//2.调用 Class 类的静态方法 forName(全类名),可能抛 ClassNotFoundException 异
常
Class clazz2 = Class.forName("com.wxkj.exer.Animal");
System.out.println(clazz2);
//3.通过运行时类的对象的 getClass()方法获取
Person p = new Person();
Class clazz3 = p.getClass();
System.out.println(clazz3);
//4.了解
ClassLoader classLoader = this.getClass().getClassLoader();
Class clazz4 = classLoader.loadClass("com.wxkj.exer.Animal");
3 通过 Class 对象可以创建运行时类(即 Class 对象对应的类)的对象,以及获取运行时类完整的类结构
3.1)
Person p = (Person)clazz.newInstance();
Constructor constructor = clazz.getDeclaredConstructor(String.class,Integer.class);
Person p1 = (Person)constructor.newInstance("小明",23);
3.2)通过 Class 对象获取类的完整结构:包名、实现的接口、父类、带泛型的
父类、注解(类上、属性、方法、构造器)、属性、方法、构造器、内部类
以及对应的属性的修饰符、声明的类型、名字;方法的修饰符、返回
值类型、方法名、形参列表
4 创建运行时类的对象,并获取、调用指定的类结构
【典型代码 1】创建运行时类的对象,并获取指定的属性为其赋值
@Test
public void getOneField() throws Exception{
//1.创建运行时类的对象
Class clazz = Person.class;
Person p = (Person)clazz.newInstance();
System.out.println(p);
//2.获取运行时类对象的属性
Field field = clazz.getField("name");
//如果属性声明为 private,那么只能 getDeclaredField(String str)的方式调
用
Field field1 = clazz.getDeclaredField("age");
//3.给运行时类的对象的相应属性赋值
//field.set(Object obj,赋值 a): 给 obj 的对象对应的 field 属性赋值为 a。 field.set(p, "小丽");
//当试图对声明为 private 的属性进行修改时,必须先调用属性的
setAccessible(true),方可对属性进行修改(赋值)
field1.setAccessible(true);
field1.set(p, 22);
//4.输出此对象
System.out.println(p);
}
【典型代码 2】创建运行时类的对象,并获取指定的方法(考虑给方法的形参赋
值)供对象调用。
@Test
public void getOneMethod() throws Exception{ //1.创建运行时类的对象
Class clazz = Person.class;
Person p = (Person)clazz.newInstance();
//2.获取运行时类对象的方法
Method method = clazz.getMethod("display", String.class,Integer.class);
Method method1 = clazz.getDeclaredMethod("show", null);
//3.调用运行时类的对象的方法,同时若方法有形参,需要给形参赋值。
//invoke(Object obj,Object...args): 给 obj 对象相应方法的形参赋值为
Object...args
method.invoke(p, "张三",33);
//System.out.println(method);
//当试图对声明为 private 的方法进行调用时,必须先调用方法的
setAccessible(true),方可对方法进行调用
method1.setAccessible(true);
method1.invoke(p, null);
}