反射
概念:将类的各个组成部分封装为其他对象。
好处:1、可以在程序的运行过程中操作对象。
2、降低程序的耦合性,提高程序的可扩展性。
看下面的图:反射将在写好的代码中,成员变量,构造方法,成员方法各自拿出进行封装,封装为不同的类。后续就对这些封装好的类进行操作。
反射获取字节码Class对象的三种方式:对应三种不同阶段
1、forName获取: //类还未调用时获取
Class<?> class1 = Class.forName("路径比如xxx.xx.x");
2、通过类名点class获取class对象 //还未创建对象时获取
这种是最简单的获取方法,例如:
Class<?> class1 = 类名.class;
3、getClass获取 //创建对象后获取
注意:getClass获取前需要先有对象,再通过类名点class获取。
比如:Person person = new Person();
Class<?> class1 = person.getClass();
Class对象功能:
1、获取成员变量:Field[ ] getFields(); 获取某个类的public修饰的成员变量,包括父类的成员变量
Field getField(String name); 获取某一个public修饰的成员变量。
Field[ ] getDeclaredFields(); 获取某个类的所有的成员变量(包括private,父类中的不算入内)
Field getDeclaredField(String name); 获取某个类的指定成员变量。
这里private也能获取到,在反射面前没有什么私有的公有的,你的都是我的,我的还是我的。
在使用Declared的时候要忽略访问权限修饰符的安全检查 对象点setAccessible(true);不然会报错。不管是Field还是Method还是Constructor都有这个说法。
2、获取构造方法:
Constructor<?>[ ] getConstructors();
Constructor<T> getConstructor(类<?>...parameterTypes);
Constructor<?>[ ] getDeclaredConstructors();
Constructor<T> getDeclaredConstructor(类<?>...parameterTypes);
3、获取成员方法
Method[ ] getMethods();
Method getMethod(String name,类<?>...parameterTypes); //parameterTypes是参数类型
Method[ ] getDeclaredMethods();
Method getDeclaredMethod(String name,类<?>...parameterTypes);
4、获取类名
String getName();
目的:
拿到Field是想要干什么?无外乎取值和赋值
① 赋值:set方法void set(Object obj,Object value);
obj是给哪个对象赋值就是谁,value是赋值为什么内容。
② 取值:get方法,get(Object obj);
传递的参数obj为被调用的对象
构造方法是用来干什么的?为什么要获取构造方法?
① 构造方法是用来创建对象的。获取到了构造方法就可以创建对象了。
② 获取构造方法:用之前获得的class对象来调用构造方法,返回的类型为Constructor。
举例:Constructor cons1 = new Constructor(String.class , int.class);
③ 创建对象通过constructor构造出来的对象点newInstance()来实现,返回的对象类型是Object,newInstance中传的是构造这个 实例时所需要传递的真正的值。
举例:Object object1 = cons1.newInstance("csdn" , 999);
拿到方法后要调用方法,调用方法就要用到invoke();
//先获取一个Method对象,假设想要获取的是Person类的方法。
Method add1 = class1.getMethod("addName",String.class); //这儿第二个参数是方法所需传值的类型,用意在于重载的时 候可以清楚找的是哪个方法。
Person person = new Person(); //invoke方法中需要传对哪个对象调用的方法,所以这里新建一个对象。
add1.invoke(person,"张三"); //invoke传的参数,第一个是哪个对象来调用方法,第二个是调用方法时需要传的参数。
那我们要反射究竟是要干什么?
比如:写一个程序,这个程序可以在不改变类的代码前提下,帮我们创建任意类的对象,执行其中的方法。
//需要用到反射,配置文件(Properties类,以键值对形式进行参数配置)。
//可以将这任意的类放置到配置文件中,再通过反射加载文件,创建对象,执行方法。
补充:
① 构造方法为空参时创建对象可以简化:
直接使用Class对象的newInstance方法来创建。
举例:Object object1 = class1.newInstance();
② 同一个字节码文件(.class)在一次程序运行过程中,只会被加载一次,不管是通过哪一种方式获取的Class对象,都是同一个。
③ 获取Class对象的三种方式:forName:通常用于配置文件中
类名.class:多用于参数的传递
对象.getClass() :多用于对象获取字节码的方式