反射:框架设计的灵魂
*框架:半成品软件。可以在框架的基础上进行软件开发,简化编码
其实,用框架并不一定用得到反射。但是,如果你要开发一套框架供别人使用,就得用到反射。但是,如果我们知道了反射机制,就能在使用框架时游刃有余。
*反射:将类的各个组成部分封装为其他对象,这就是反射机制。
例如:将成员变量封装为Field对象;构造函数-->Constructor对象;成员方法-->Method对象
*获取class对象的方式:
1.Class.forName("全类名");将字节码文件加载进内存,返回Class对象(对应源代码阶段)*多用于配置文件,将类名定义在配置文件中,返回class对象
2.类名.class:通过类名的属性class获取(对应class类对象阶段)*多用于参数的传递
3.对象.getClass():getClass()方法在Object类中定义着 *多用于对象的获取字节码的方式
结论:同一个字节码文件(*.class)在一次程序运行过程中,只会被加载一次,不论通过哪一种方式获取的class对象都是同一个。
好处:1.可以在程序的运行过程中去操作这些对象。例如,String str 这个对象创建之后,str. 后会提示很多方法。这些方法其实就是str对象加载到内存之后,程序运行中程序提供的操作这些对象的方式。
/*Class对象功能: *获取功能: 1.获取成员变量们: *Field[] getFields();---获取所有public 修饰的成员变量 *Field getField(String name)----获取指定名称的public修饰的成员变量 *Field[] getDeclaredFields()----获取所有成员边浪 *Field getDeclaredField(String name) * *操作: *1.设置值 2.获取值 *2.获取构造方法们 *Constructor<> getConstructors() *Constructor<> getConstructor(类<>..parameterTypes) *Constructor<> getDeclaredConstructor(类<>..parameterTypes) *Constructor<>[] getDeclaredConstructor() * *3.获取成员方法们: *Method[] getMethods() *Method getMethod(String name,类<>...parameterTypes) *Method[] getDeclaredMethods() *Method getDeclaredMethod(String name,类<>..parameterTypes) * *4.获取类名 *String getName() */
2.可以解耦。来达到程序的可扩展性。
package cn.itcast.junit; import java.text.DateFormat.Field; public class ReflectDemo { public static void main(String[] args) throws SecurityException, NoSuchFieldException, IllegalArgumentException, IllegalAccessException { //获取Person的class对象 Class personClass=Person.class; /*1.获取成员变量们: *Field[] getFields(); *Field getField(String name) *Field[] getDeclaredFields() *Field getDeclaredField(String name) **/ //1.Field[] getFields();---获取所有public 修饰的成员变量 java.lang.reflect.Field[] Feilds=personClass.getFields(); for(java.lang.reflect.Field filed:Feilds){ System.out.println(filed); //public java.lang.String cn.itcast.junit.Person.a } //*Field getField(String name)----获取指定名称的public修饰的成员变量 Person p=new Person();
、 //Field 是对象 。对象就有方法。通过对象的方法完成操作。具体操作参见API文档 java.lang.reflect.Field f=personClass.getField("a");
、 //此时 f 为获取的 person 类中的String a 参数。如下对 f 进行设置值与赋值 f.set(p, "这是通过设置成员方法设置的值");//操作成员变量---设置成员变量的值 Object value=f.get(p); System.out.println(value); //*Field[] getDeclaredFields() System.out.println("\n================="); java.lang.reflect.Field[] filed = personClass.getDeclaredFields(); for(java.lang.reflect.Field f1:filed){ System.out.println(f1); } //*Field getDeclaredField(String name) //这里不能访问 d java.lang.reflect.Field f3=personClass.getDeclaredField("d"); Person p2=new Person(); //会报错 //f3.set(p2, "这是通过获取成员变量而设置的值"); //System.out.println(f3.get(p2)); //访问前忽略权限修饰符的安全检查---"暴力反射" f3.setAccessible(true); f3.set(p2, "这是暴力反射后获取成员变量而设置的值"); System.out.println(f3.get(p2)); } }
案例:
*需求:写一个“框架”,可以帮我们创建任意类的对象,并且执行其中任意的方法(在不改变该类的任何代码的前提下)。
*实现:
1.配置文件 2.反射
*步骤
1.将需要创建的对象的全类名和需要执行的方法定义在配置文件中
2.在程序中加载读取配置
3.使用反射技术来加载类文件进内存
4.创建对象
5.执行方法
文件列表+配置文件:(实现在不改变任何源代码的前提下,通过改变配置文件来达到获取不同类下的不同方法,并执行)
package cn.itcast.reflection; import java.io.IOException; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.Properties; import org.omg.CORBA.portable.InputStream; /* * 框架类 * */ public class ReflectTest { //可以创建任意类的对象,可以执行任意方法 public static void main(String[] args) throws IOException, ClassNotFoundException, InstantiationException, IllegalAccessException, SecurityException, NoSuchMethodException, IllegalArgumentException, InvocationTargetException { /*前提:不能改变该类的任何代码,可以创建任意类的对象,可以执行任意方法*/ //1.加载配置文件 //1.1 创建Properties对象 Properties pro =new Properties(); //1.2加载配置文件,转换为一个集合 //1.2.1 获取文件class目录下的配置文件 ClassLoader classLoader=ReflectTest.class.getClassLoader(); java.io.InputStream is=classLoader.getResourceAsStream("pro.properties"); System.out.println(is); pro.load(is); //2.获取配置文件中配置的数据 String className=pro.getProperty("className"); //System.out.println(className); String methodName=pro.getProperty("methodName"); //System.out.println(methodName); //3.加载该类进内存 Class cls=Class.forName(className); //创建对象 Object obj=cls.newInstance(); //System.out.println(obj); //获取方法对象 Method method=cls.getMethod(methodName); //执行方法 method.invoke(obj); } }