在运行状态中,对于任意一个类(class文件),都能够知道这个类的所有属性和方法,并能够实例化该类成对象,并调用其方法和成员。这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。
JAVA中的反射机制是一种能够大大增强程序扩展性的技术。当一个程序封装完成后(生成exe文件),如果想要对该程序进行功能扩展,不用进行代码的重新修改(也不可能拿到源码),只要修改配置文件(一般是XML)就可以完成扩展。
这样的程序为外部提供了一个接口,只要按照该接口的规则定义一个对象(功能),即可以为应用程序扩展该功能。
可以这样比喻,你买了一块电脑主板(封装好的程序),此时你想要添加一块声卡(要扩展的功能),此时只能够通过一个pci接口(应用程序提供的接口)来进行扩展。声卡的接口必须符合PCI的规则才可以被主板使用。通过添加驱动程序(修改XML配置文件)来进行扩展功能。
具体到代码实现分为以下几步:
1、定义一个接口(PCI)及一系列的方法用作加载功能。
2、定义一个对象并且实现该接口,复写其中的方法。
3、在配置文件中添加该对象的名称(全名,包括路径)键值对。
4、定义一个输入流,读入配置文件进properties集(健壮性判断);
5、使用for循环挨个获取properties集中的对象名称;
6、获取名称后用Class加载这个类,并实例化一个该对象(可以直接进行类型强转,因为已知是PCI接口)。
7、使用对象。
1 File configFile = new File("pci.properties"); 2 3 Properties prop = new Properties(); 4 FileInputStream fis = new FileInputStream(configFile); 5 6 prop.load(fis); 7 8 for(int x=0; x<prop.size(); x++){ 9 10 String pciName = prop.getProperty("pci"+(x+1)); 11 12 Class clazz = Class.forName(pciName);//用Class去加载这个pci子类。 13 14 PCI p = (PCI)clazz.newInstance(); //PCI接口已经定义好了,有open和close两个方法 15 16 mb.usePCI(p);//mb是主板对象,定义了一个使用PCI接口对方法 17 } 18 19 fis.close();
不仅如此,有时还需要或得该对象的有参数构造器,成员,成员方法
1、创建对象实例
//1、指定该类的名称 String className = "cn.itcast.bean.Person"; //2、通过Class类的forName()方法获取该类(从.class文件中获取) Class clazz = Class.forName(className); //3、通过Class对象的newInstance()方法创建对象,无参构造器 Object obj = clazz.newInstance();
问题:
1、从上面代码可以发现,如果要用有参构造器实例化对象的话就不行
2、实例化的对象时Object类,要想办法downcast
2、获取其任意构造器
String name = "cn.itcast.bean.Person"; //1、找寻该名称类文件,并加载进内存,并产生Class对象。 Class clazz = Class.forName(name); //2、获取到了指定的构造函数对象,构造器也有自己的对象。getConstructor(,)的参数列表对应于所需构造器的参数列表的类对象 Constructor constructor = clazz.getConstructor(String.class,int.class); //3、通过该构造器对象的newInstance方法进行对象的初始化。 Object obj = constructor.newInstance("小明",38);
3、获取其成员
Class clazz = Class.forName("cn.itcast.bean.Person"); Field field = null; //clazz.getField("age");//只能获取公有的, field = clazz.getDeclaredField("age");//只获取本类,但包含私有。 参数为成员名 //对私有字段的访问取消权限检查。暴力访问。 field.setAccessible(true); Object obj = clazz.newInstance(); field.set(obj, 89);//将obj对象中的对应field成员值设为89 Object o = field.get(obj);//返回obj对象中的field成员的值 System.out.println(o);//89
4、获取方法(类似于构造器的获取)
public static void getMethodDemo_3() throws Exception { Class clazz = Class.forName("cn.itcast.bean.Person"); Method method = clazz.getMethod("paramMethod", String.class,int.class);//第一个参数是方法名,考虑到重载,所以后面要加上参数列表来定位唯一的方法 Object obj = clazz.newInstance(); method.invoke(obj, "小强",89);//调用obj对象中的method方法,且传递了参数。 } public static void getMethodDemo() throws Exception { Class clazz = Class.forName("cn.itcast.bean.Person"); Method[] methods = clazz.getMethods();//获取的都是公有的方法。 methods = clazz.getDeclaredMethods();//只获取本类中所有方法,包含私有。 返回一个方法数组,方法对象数组 for(Method method : methods){ System.out.println(method); } }