一、创建对象
通过反射创建对象有两种方式:
1、 使用Class对象的newInstance()方法,这种方法实际上是使用默认的构造器起来创建该类的实例
2、使用Class对象获取指定的Constructor对象,调用Constructor对象的newInstance()方法来获取来创建该Class的实例,这样可以根据参数类型来指定使用哪个构造器。
下面代码实现一个简单工厂类,该工厂类可以根据配置文件产生Object类的子类
public class ObjectFactory { private static String propertiesFileName; private static Map<String, Object> objectPool; public static String getPropertiesFileName() { return propertiesFileName; } public static void setPropertiesFileName(String propertiesFileName) { ObjectFactory.propertiesFileName = propertiesFileName; } public static Object getObject(String key) { if (objectPool.isEmpty()) { try ( FileInputStream fis = new FileInputStream(propertiesFileName) ) { Properties props = new Properties(); props.load(fis); for (String name : props.stringPropertyNames()) { objectPool.put(name,CreatObject(props.getProperty(name))); } } catch (Exception e) { e.printStackTrace(); } } return objectPool.get(key); } public static Object CreatObject(String className)throws ClassNotFoundException,IllegalAccessException,InstantiationException{ Class clazz = Class.forName(className); return clazz.newInstance(); } }
二、调用方法
由Class对象可以获得该Class的Method对象,调用Method对象的invoke()方法可以调用该Method,下面为该方法签名:
返回值Object即为执行方法后的返回值,第一个参数obj指定由哪个对象来执行该方法,后面的args参数代表执行该方法传入的参数。在调用invoke方法是要注意访问修饰符的权限。使用isAccessible方法来判断,使用setAccessible方法来判断权限。
如果调用的方法为静态方法,则第一个参数为null。
下面代码对上面的对象工厂加强,允许在配置文件中增加配置对象的的成员变量的值,对象工厂会读取配置并利用对象的setter方法设置成员变量的值。
由于这个例子用作实验反射调用方法,所以另外实现了一个简单工厂类,而没有使用工厂模式将工厂类抽象出来便于拓展。
public class ExtendObjectFactory { private static String propertiesFileName; private static Map<String, Object> objectPool; public static String getPropertiesFileName() { return propertiesFileName; } public static void setPropertiesFileName(String propertiesFileName) { ExtendObjectFactory.propertiesFileName = propertiesFileName; } public static Object CreatObject(String className)throws ClassNotFoundException,IllegalAccessException,InstantiationException{ Class clazz = Class.forName(className); return clazz.newInstance(); } public static Object getObject(String key){ if (objectPool.isEmpty()) { try ( FileInputStream fis = new FileInputStream(propertiesFileName) ) { Properties props = new Properties(); props.load(fis); for (String name : props.stringPropertyNames()) { // objectPool.put(name,CreatObject(props.getProperty(name))); //取出每一对key-value对,如果key中包含百分号,则认为该key用于控制对象的setter方法设置值,%前半为对象名字,后半控制setter方法名 if(name.contains("%")){ String[] objAndProp = name.split("%"); Object target = objectPool.get(objAndProp[0]); String methodName = "set" + objAndProp[1].substring(0,1).toUpperCase()+objAndProp[1].substring(1); Class targetClass = target.getClass(); Method setterMethod = targetClass.getMethod(methodName,String.class); setterMethod.invoke(target,props.getProperty(name)); }else { objectPool.put(name,CreatObject(props.getProperty(name))); } } } catch (Exception e) { e.printStackTrace(); } } return objectPool.get(key); } }
配置文件的格式可以如同这般
1 a=javax.swing.JFrame 2 b=javax.swing.JLabel 3 #set the title of a 4 a%title=Test Title
三、访问成员变量的值
Field类提供了如下两组方法:
getXxx(Object obj) :获取obj对象的的该成员变量的值,此处的Xxx指8种基本类型,若成员变量的类型为引用类型,则取消后面的Xxx。
setXxx(Object obj,Xxx val) 类似于上面的方法。
四、操作数组
java.lang.reflect包下还提供了一个Array类,Array对象可以代表所有的数组,程序可以使用Array来动态创建数组,操作数组。
Array类提供的方法签名:
length参数是可变个数参数,有几个length参数就是几维数组,三维数组的元素是二维数组,二维数组的元素是一维数组。
五、其他的操作不再一一演示,用的时候查阅文档即可