近来封装了很多发射的小方法,使用过程中,发觉发射的好处是:当很多类有共性时,使用发射,可以达到只做一次,到处使用的效果。就像Hibernate一样,save(obj),我并不需要知道obj到底是哪个类,Hibernate自动会正确的把记录保存到数据库!
备注:
我使用反射封装一些小方法,是为了对大部分有共性的方法通用,所以要求,
a.类的属性必须有getXXX与setXXX方法;
b.getXXX,setXXX,XXX必须与类的字段名一致,而首字母大写;
c.getXXX是无参的,setXXX参数只能有1个,而且类型必须与属性一致(除了基础数据类型,他们可以自动打包)
d.最好有一个无参构造函数
我将有关反射的方法都放入了BeanReflectUtil,作为工具类使用。
准备一个简单的类(我的小方法也就只能对简单的类其作用)
public class Person {
private String name;
private int age;
private Date birthday;
public Person() {
}
public Person(String name, int age, Date birthday) {
super();
this.name = name;
this.age = age;
this.birthday = birthday;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public Date getBirthday() {
return birthday;
}
public void setBirthday(Date birthday) {
this.birthday = birthday;
}
}
1.封装getter
/***
* 组装类中某个属性的get方法名称
* StringUtil.upperFirst(String str)是自己封装的,将首字母变大小的小方法;
* @param c
* @param filedName
* @return
* @throws SecurityException
* @throws NoSuchMethodException
*/
public static Method assembleGetMethod(Class<?> c, String filedName) throws SecurityException, NoSuchMethodException {
String methodName = "get" + StringUtil.upperFirst(filedName);
Class<?>[] nullClasses = null;
return c.getDeclaredMethod(methodName, nullClasses);
}
调用方法实例:
Method m = BeanReflectUtil.assembleGetMethod(Person.class, "name");
m.invoke(new Person("jack"), null);
为了进一步——偷懒,将封装一个小方法:
public static Object invokeGetMethod(Class<?> c, String filedName, Object obj)
throws SecurityException, NoSuchMethodException, IllegalArgumentException,
IllegalAccessException, InvocationTargetException {
Method method = assembleGetMethod(c, filedName);
Object[] nullObjects = null;
return method.invoke(obj, nullObjects);
}
那么,我们使用某个属性的getter方法时,只需要
BeanReflectUtil.invokeGetMethod(Person.class, "name", new Person("jack"));
就可以了。
2.封装setter方法
与getter方法不一样的地方是:getXXX()是无参的,
所以,封装的时候,需要告诉他参数的类型;调用的时候,要给一个参数!
/***
* 组装类中某个属性的set方法名称
* @param c 要封装哪个类
* @param filed 封装哪个属性
* @return
* @throws SecurityException
* @throws NoSuchMethodException
*/
public static Method assembleSetMethod(Class<?> c, Field field)
throws SecurityException, NoSuchMethodException {
String methodName = "set" + StringUtil.upperFirst(field.getName());
Class<?>[] parameterClasses = new Class[]{field.getType()}; //告诉Java该set方法的参数类型
return c.getDeclaredMethod(methodName, parameterClasses);
}
调用:
Method setMethod = BeanReflectUtil.assembleSetMethod(Person.class, Person.class.getDeclaredField("name"));
Person p = new Person();
setMethod.invoke(p, "jack");
System.out.println(p.getName());
想进一步偷懒,可以
/**
* 封装Set方法,并立刻调用
* @param c 为哪个类封装Set方法
* @param fieldName 属性名称
* @param obj 为哪个对象赋值
* @param fieldValue 赋的值
*/
public static void invokeSetMethod(Class<?> c, String fieldName, Object obj, Object fieldValue)
throws SecurityException, NoSuchFieldException,
NoSuchMethodException, IllegalArgumentException,
IllegalAccessException, InvocationTargetException {
Field f = c.getDeclaredField(fieldName);
Method setMethod = assembleSetMethod(c, f);
setMethod.invoke(obj, fieldValue);
}
调用方法:
invokeSetMethod(Person.class, "name", p, "Mike");
System.out.println(p.getName());
但,实际使用中,应该不会用到,
我的想象场景是:有一堆Map<Person p, String name>
我获得set方法后,会为很多Map中的Person的name属性赋上Map中的name值,
所以,不会组装好set后就马上调用,这样效率也太低了。