問題引入
需要將不同的兩個(gè)對(duì)象實(shí)例進(jìn)行屬性復(fù)制,從而基于源對(duì)象的屬性信息進(jìn)行后續(xù)操作,而不改變?cè)磳?duì)象的屬性信息,比如DTO數(shù)據(jù)傳輸對(duì)象和數(shù)據(jù)對(duì)象DO,我們需要將DO對(duì)象進(jìn)行屬性復(fù)制到DTO,但是對(duì)象格式又不一樣,所以我們需要編寫映射代碼將對(duì)象中的屬性值從一種類型轉(zhuǎn)換成另一種類型。
這種轉(zhuǎn)換最原始的方式就是手動(dòng)編寫大量的 get/set
代碼,當(dāng)然這是我們開發(fā)過程不愿意去做的,因?yàn)樗_實(shí)顯得很繁瑣。為了解決這一痛點(diǎn),就誕生了一些方便的類庫(kù),常用的有 apache的 BeanUtils
,spring的 BeanUtils
,這些庫(kù)可以幫助我們輕松的實(shí)現(xiàn)對(duì)象屬性的拷貝而不需要我們?cè)偈謩?dòng)get/set.
在介紹之前,我們先來看下關(guān)于對(duì)象拷貝的前置知識(shí),淺拷貝和深拷貝。
前置知識(shí)
如果在拷貝這個(gè)對(duì)象的時(shí)候,只對(duì)基本數(shù)據(jù)類型進(jìn)行了拷貝,而對(duì)引用數(shù)據(jù)類型只是進(jìn)行引用的傳遞,而沒有真實(shí)的創(chuàng)建一個(gè)新的對(duì)象,則認(rèn)為是淺拷貝。反之,在對(duì)引用數(shù)據(jù)類型進(jìn)行拷貝的時(shí)候,創(chuàng)建了一個(gè)新的對(duì)象,并且復(fù)制其內(nèi)的成員變量,則認(rèn)為是深拷貝。
簡(jiǎn)單來說:
- 淺拷貝:對(duì)基本數(shù)據(jù)類型進(jìn)行值傳遞,對(duì)引用數(shù)據(jù)類型進(jìn)行引用傳遞般的拷貝,此為淺拷貝
- 深拷貝:對(duì)基本數(shù)據(jù)類型進(jìn)行值傳遞,對(duì)引用數(shù)據(jù)類型,創(chuàng)建一個(gè)新的對(duì)象,并復(fù)制其內(nèi)容,此為深拷貝。
BeanUtils
Apache 的 BeanUtils
beantutils 對(duì)于對(duì)象拷貝加了很多的檢驗(yàn),包括類型的轉(zhuǎn)換,甚至還會(huì)檢驗(yàn)對(duì)象所屬的類的可訪問性,可謂相當(dāng)復(fù)雜,這也造就了它的差勁的性能,在Java開發(fā)手冊(cè)中也提到盡量避免使用Apache 的 BeanUtils 工具類。
使用案例(注意參數(shù)的順序)
public class PersonSource {
private Integer id;
private String username;
private String password;
private Integer age;
// getters/setters omiited
}
public class PersonDest {
private Integer id;
private String username;
private Integer age;
// getters/setters omiited
}
public class TestApacheBeanUtils {
public static void main(String[] args) throws InvocationTargetException, IllegalAccessException {
//下面只是用于單獨(dú)測(cè)試
PersonSource personSource = new PersonSource(1, "pjmike", "12345", 21);
PersonDest personDest = new PersonDest();
BeanUtils.copyProperties(personDest,personSource);
System.out.println("persondest: "+personDest);
}
}
persondest: PersonDest{id=1, username='pjmike', age=21}
Spring 的 BeanUtils
spring下的BeanUtils也是使用 copyProperties
方法進(jìn)行拷貝,只不過它的實(shí)現(xiàn)方式非常簡(jiǎn)單,就是對(duì)兩個(gè)對(duì)象中相同名字的屬性進(jìn)行簡(jiǎn)單的get/set,僅檢查屬性的可訪問性。
使用案例(注意參數(shù)的順序,和Apache相反)
public class TestSpringBeanUtils {
public static void main(String[] args) throws InvocationTargetException, IllegalAccessException {
//下面只是用于單獨(dú)測(cè)試
PersonSource personSource = new PersonSource(1, "pjmike", "12345", 21);
PersonDest personDest = new PersonDest();
BeanUtils.copyProperties(personSource,personDest);
System.out.println("persondest: "+personDest);
}
}
小結(jié)
以上簡(jiǎn)要的分析兩種BeanUtils,因?yàn)锳pache下的BeanUtils性能較差,不建議使用,可以使用 Spring的BeanUtils,或者使用其他拷貝框架,比如 cglib BeanCopier,基于javassist的Orika等,這些也是非常優(yōu)秀的類庫(kù)。注意這種都是淺拷貝!!!