在Struts中经常看到BeanUtils.copyProperties这个方法满天飞,特别是在提取表单中的值的时候,但是这个方法具体怎么实现属性的复制却一直不是很明白,特别是在复制属性的时候,比方说把b复制到a,BeanUtils.copyProperties(a,b),是不是把b的所有属性都复制过去了呢?如果是同一个属性,b中的值是不是会覆盖掉a中的值?这些应该都可以从BeanUtils的源码中得到答案,奈何找了半天没找到源码,在网上也没有找到别人的答复,于是本着实践是检验真理的唯一标准,决定亲自测试一把,^_^。
首先我们构建两个类People和Person,它们的实例呆会会用来相互复制。
People.java:
package com.mangocity.test;
/**
* @author CMTobby
*/
public class People {
public People() {
// TODO Auto-generated constructor stub
}
private String name;//姓名
private int age;//年龄
private String email;
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
Person.java:
package com.mangocity.test;
/**
* @author CMTobby
*/
public class Person {
private String name;
private int age;
private String address;
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
接着构建我们的测试类
import org.apache.commons.beanutils.*;
public class TestBeanUtils {
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
People tobby=new People();
Person cindy=new Person();
tobby.setAge(23);
tobby.setName("CMTobby");
tobby.setEmail("xiaozhu87487705@163.com");
cindy.setName("Cindyelf");
cindy.setAge(24);
try {
BeanUtils.copyProperties(cindy, tobby);
System.out.println(cindy.getName()+":"+cindy.getAge());
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InvocationTargetException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
运行该程序输出是:CMTobby:23。这说明经过BeanUtils.copyProperties之后cindy中name和age属性的值已经被tobby中的同名属性给“覆盖”了,至于tobby中有而cindy中没有的email属性有没有复制到cindy中就不得而知了,据我的猜测应该是没有的,因为在cindy中没有地方放这个属性啊,而且就算复制过去了,我们如何得到这个值呢?难道用cindy.getEmail()吗,可是cindy根本没有这个方法啊?当然这只是我的猜测,不知哪位达人有准确的答案,欢迎指正,^_^。
那么这个复制过程是如何的呢?是直接属性对属性的值拷贝吗,例如cindy.name=tobby.name?还是老办法,将测试进行到底。
1.我将Person中的name属性改名为name11,age属性改为age11,get和set方法都做相应的修改,此时运行程序,输出结果为:CMTobby:23,和前面的一样,由此可以排除值拷贝这个假设了,因为此时cindy中没有了name属性而是name11属性。
2.我将Person中的setName和setAge方法分别改为setName11和setAge11.OK,再次运行我们的程序,这时的输出是:Cindyelf:24,我们发现cindy的name属性和age属性的值都没有被覆盖掉,也就是说tobby中的值都没有拷贝过来,为什么呢?
3.将我们程序恢复到刚开始的样子,即上面所贴的代码那样,然后将Person中的setAge方法注释掉,并注释掉TestBeanUtils中的cindy.setAge(24)这行代码。运行程序,输出结果是:CMTobby:0。tobby中age属性的值没有拷贝过来,为什么呢?
基于上述两个测试,我猜测BeanUtils.copyProperties的行为过程是这样的:首先通过java的反射得到tobby中的所有域,然后根据域的名字调用cindy中相应的set方法。举个例子,BeanUtils发现tobby中有个name属性,那么它会尝试执行cindy.setName()这个方法。这就很容易解释测试2和测试3的结果了:因为cindy中没有了setName或者setAge(被改成了setName11和setAge11或者被注释掉了),所有cindy的name属性不会变,仍然是以前的值。而在测试1中,因为cindy对象有setName方法,所以name11属性的值会被覆盖掉。
做完上述测试之后,我闲着无聊又做了如下两个测试:
4.将Person中的setName和setAge改为setname和setage,程序输出结果是:CMTobby:23,cindy中的name属性和age属性的值都发生了变化;
5.将Person中的setName和setAge改为setNAme和setAGe,程序输出结果是:Cindyelf:24,tobby中的属性的值都没有拷贝过来。
基于这两个测试,我想过程会不会是这样的:如果BeanUtils发现tobby中有个name属性,那么它就会尝试执行cindy.setName()或者cindy.setname()。当然这些都只是我的推论,仅供参考,所有的答案都会在BeanUtils的源码中找到,^_^,还望哪位达人不吝告知。