① 创建对象
如果知道一个类型,很容易使用new操作符创建一个类的实例。但是如果在编译时并不知道具体要实例化的是哪个类的对象,如何创建该实例呢?
Java中提供Class.forName(String className)从一个字符串(含包的类全名称)加载一个类,再利用newInstance方法创建该类的实例。
//动态创建类对象
public static Object createObject(String className) {
Object object = null;
try {
Class classDefinition = Class.forName(className);
object = classDefinition.newInstance();
} catch (InstantiationException e) {
System.out.println(e);
} catch (IllegalAccessException e) {
System.out.println(e);
} catch (ClassNotFoundException e) {
System.out.println(e);
}
return object;
}
当然,也可以先获取一个类的Constructor,再调用其newInstance方法创建对象。不同的是,constructor对象的newInstance方法需要传递一个对象数组作为构造方法的参数列表。
//使用Constructor动态创建对象
public static Object createObject(Constructor constructor, Object[] arguments) {
System.out.println("Constructor: " + constructor.toString());
Object object = null;
try {
object = constructor.newInstance(arguments);
System.out.println("Object: " + object.toString());
return object;
} catch (InstantiationException e) {
System.out.println(e);
} catch (IllegalAccessException e) {
System.out.println(e);
} catch (IllegalArgumentException e) {
System.out.println(e);
} catch (InvocationTargetException e) {
System.out.println(e);
}
return object;
}
② 获取/设置字段值
利用Reflection API获取或者设置字段的值,首先要得到Class对象,然后利用Class对象的getField方法取得相应的字段Field对象,然后调用Field对象对应的getXXX/setXXX方法获取或者设置属性的值。Filed对象提供getInt/setInt、getLong/setLong等方法对基本类型的属性进行值的获取和设置,可以直接使用get/set方法获取复杂类型属性的值(返回一个对象值/传递一个对象值作为参数)。
具体操作方法见如下代码片段。当然,若试图获取/设置一个非public的字段值(getField方法也不能获取非pubic的属性对象,可以尝试使用getDeclaredField方法),将产生IllegalAccessException,可以通过setAccessible(true)使非public的字段可见,然后对字段值进行访问。
// 获取字段值
static void getFiledValue(Object o, String filedName) {
Class c = o.getClass();
Field filed;
Object value;
try {
filed = c.getField(filedName);
// filed = c.getDeclaredField(filedName);
// filed.setAccessible(true); //修改字段访问权限
value = filed.get(o); //可使用getInt、getLong等(若知晓字段基本类型)
System.out.println(filedName + ": " + value.toString());
} catch (NoSuchFieldException e) {
System.out.println(e);
} catch (SecurityException e) {
System.out.println(e);
} catch (IllegalAccessException e) {
System.out.println(e);
}
}
// 修改字段值
public static void setFieldValue(Object o, String filedName, Object value) {
Field filed;
Class c = o.getClass();
try {
filed = c.getField(filedName);
// filed = c.getDeclaredField(filedName);
// filed.setAccessible(true); //修改字段访问权限
filed.set(o, value); //可使用setInt、setLong等(若知晓字段基本类型)
} catch (NoSuchFieldException e) {
System.out.println(e);
} catch (IllegalAccessException e) {
System.out.println(e);
}
}
③ 调用方法
方法调用的过程类似于设置字段值的过程,首先要得到Class对象,然后调用getMethod方法得到方法Method的对象,getMethod方法要求传递两个参数,一个是方法名,第二个是Class[],即方法参数列表中各参数对应的类型的数组。然后执行Method对象的invoke方法,进行方法的调用,invoke方法需要传递两个参数,第一个是方法绑定的对象,第二个是方法的参数列表。如果是static的方法,则第一个参数将自动被忽略(可为null)。
同理,对于非public的方法,可以使用getDeclaredMethod方法获取Method对象,并使用setAccessible设置其可见性。
//动态调用方法
public static Object callMethod(Object o, String methodName,
Class paramsType[], Object paramsValue[]) {
Object result = null;
Class c;
Method method;
try {
c = o.getClass();
method = c.getMethod(methodName, paramsType);
// method = c.getDeclaredMethod(methodName, paramsType);
// method.setAccessible(true);
result = method.invoke(o, paramsValue);
} catch (NoSuchMethodException e) {
System.out.println(e);
} catch (IllegalAccessException e) {
System.out.println(e);
} catch (InvocationTargetException e) {
System.out.println(e);
}
return result;
}