BeanUtils和PropertyUtils类是许多开源框架中频繁使用的两个工具,它们都能实现将一个类中的属性拷贝到另一个类中,这个功能甚至是spring实现依赖注入的基础。研究一下apache的comon包中如何实现这个两个工具,可以发现它们都是使用java.lang.reflect和java.beans这两个包下的几个类来实现的。
这里我们通过编写一个将一个类的所有属性拷贝到另一个类的相应属性的方法来分析是如何实现拷贝功能的.先把方法放上来:
/** 实现将源类属性拷贝到目标类中
* @param source
* @param target
*/
public static void copyProperties(Object source, Object target) {
try {
//获取目标类的属性信息
BeanInfo targetbean = Introspector.getBeanInfo(target.getClass());
PropertyDescriptor[] propertyDescriptors = targetbean.getPropertyDescriptors();
//对每个目标类的属性查找set方法,并进行处理
for (int i = 0; i < propertyDescriptors.length; i++) {
PropertyDescriptor pro = propertyDescriptors[i];
Method wm = pro.getWriteMethod();
if (wm != null) {//当目标类的属性具有set方法时,查找源类中是否有相同属性的get方法
BeanInfo sourceBean = Introspector.getBeanInfo(source.getClass());
PropertyDescriptor[] sourcepds = sourceBean.getPropertyDescriptors();
for (int j = 0; j < sourcepds.length; j++) {
if (sourcepds[j].getName().equals(pro.getName())) { //匹配
Method rm = sourcepds[j].getReadMethod();
//如果方法不可访问(get方法是私有的或不可达),则抛出SecurityException
if (!Modifier.isPublic(rm.getDeclaringClass().getModifiers())) {
rm.setAccessible(true);
}
//获取对应属性get所得到的值
Object value = rm.invoke(source,new Object[0]);
if (!Modifier.isPublic(wm.getDeclaringClass().getModifiers())) {
wm.setAccessible(true);
}
//调用目标类对应属性的set方法对该属性进行填充
wm.invoke((Object) target, new Object[] { value });
break;
}
}
}
}
} catch (IntrospectionException e) {
e.printStackTrace();
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
两个工具的其他方法实现虽然有点差别,但原理都跟上面的例子差不多,有兴趣的话可以写个测试类试试是否可以使用.