一、创建对象
通过反射创建对象有两种方式:
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参数就是几维数组,三维数组的元素是二维数组,二维数组的元素是一维数组。
五、其他的操作不再一一演示,用的时候查阅文档即可