反射
一、反射的概念
一个类有多个组成部分,例如:成员变量、方法、构造函数等。反射就是加载类,并解剖出类的各个组成部分。反射通常用来开发框架。
二、加载类
使用反射的第一步就是加载类,Java中的CLass类用于代表某一个类的字节码,它提供了加载某个;类字节码的方法:forName()。forName方法用于加载某个类的字节码到内存中,并使用class对象进行封装。
使用forName()时必须提供需要加载的类的完整名称,例如:
class.forName("cn.itcast.reflect.Person");
其中cn.itcast.reflect为上级包名,Person为类名,使用该方法后,就将该类的字节码从硬盘中加载进内存了。
获取字节码的另外两种方式:
Class cla=new Person().getClass();
Class cla=Person.class;
三、使用Class对象提供的方法反射类的成员
反射构造函数:
//加载类
Class cla=class.forName("cn.itcast.reflect.Person");
//使用getConstructor解剖出公有无参构造函数,并返回Constructor对象。
Constructor cst=cla.getConstructor(null);
//使用 Constructor的newInstance方法创建对象
Person p=(Person)cst.newInstance(null);
getConstructor只能得到公有的构造函数,如果想获得私有的构造函数,则需要调用 getDeclaredConstructor方法,并实现暴力反射。
//解剖出私有无参的构造函数,并返回Constructor对象
Constructor cst=cla.getDeclaredConstructor(null);
//实现暴力反射
cst.setAccessible(true);
创建对象还有另外一种方法:
//直接通过Class的newInstance方法来创建对象,但使用这种方法是默认调用了无参的构造方法,所以类中必须要有无参的构造方法
Person p=(Person)cla.newInstance();
反射类的方法:
//加载类
Class cla=class.forName("cn.itcast.reflect.Person");
//使用getMethod解剖出.Person类中的方法,并返回Method对象。
Method met=cla.getMethod(Object obj,Object obj);//前面为方法名,后面为参数类型
//调用解剖出来的方法
met.invoke(Object obj,Object… obj);//前面为方法名,后面为参数
getMethod只能得到公有的方法,如果想获得私有的方法,则需要调用 getDeclaredMethod方法,并实现暴力反射。
//解剖出Person类中的方法,并返回Method对象。
Method met=cla.getDeclaredMethod(Object obj,Object obj);//前面为方法名,后面为参数类型
//实现暴力反射
met.setAccessible(true);
//调用解剖出来的方法
met.invoke(Object obj,Object… obj);//前面为方法名,后面为参数
如果该方法为静态,则使用invoke调用方法时不需要传递对象。
met.invoke(null,Object… obj);
如果解剖的方法是主方法,使用invoke调用方法时传递的参数时,会默认将数组拆开取其中的元素,所以必须对参数进行处理。
met.invoke(null,(Object)new String[2]);
反射类的字段:
//加载类
Class cla=class.forName("cn.itcast.reflect.Person");
//使用getField解剖出.Person类中的字段,并返回Field对象。
Field fd=cla.getField(Object ob);//参数为字段名
//使用 Field的get方法传递对象,获得字段,并返回object对象。
fd.get(Object obj);
//使用Field的getType方法可以返回字段的类型
fd.getType();
//使用 Field的set方法传递对象和值,给该字段赋值。
fd.set(Object obj,Object obj);//前面为对象,后面为要赋的值
getField只能得到公有的字段,如果想获得私有的字段,则需要调用 getDeclaredField方法,并实现暴力反射。
//解剖出类的私有字段,并返回Field对象。
Field fd=cla.getDeclaredField(Object ob);//参数为字段名
//实现暴力反射
fd.setAccessible(true);