在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("[email protected]");
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的源碼中找到,^_^,還望哪位達人不吝告知。