Spring的BeanUtils.copyProperties屬性復(fù)制避坑指南
Spring的BeanUtils.copyProperties屬性復(fù)制避坑
項(xiàng)目場(chǎng)景:
在分布式項(xiàng)目中,我進(jìn)行我們的項(xiàng)目對(duì)外接口整合時(shí),需要自己再定義對(duì)外的類(lèi)來(lái)傳參,就避免不了用BeanUtils.copyProperties工具來(lái)進(jìn)行屬性賦值。
問(wèn)題描述
關(guān)于BeanUtils.copyProperties的屬性復(fù)制規(guī)則
話(huà)不多說(shuō)直接上demo代碼
- 類(lèi)A
class A { int a; List<Integer> list = new ArrayList<>(); List<B> bList = new ArrayList<>(); B b; public int getA() { return a; } public void setA(int a) { this.a = a; } public B getB() { return b; } public void setB(B b) { this.b = b; } public List<Integer> getList() { return list; } public void setList(List<Integer> list) { this.list = list; } public List<B> getbList() { return bList; } public void setbList(List<B> bList) { this.bList = bList; } @Override public String toString() { return "A{" + "a=" + a + ", list=" + list + ", bList=" + bList + ", b=" + b + '}'; } }
- 類(lèi)A1
class A1 { int a; List<Integer> list = new ArrayList<>(); List<B> bList = new ArrayList<>(); B b; public int getA() { return a; } public void setA(int a) { this.a = a; } public B getB() { return b; } public void setB(B b) { this.b = b; } public List<Integer> getList() { return list; } public void setList(List<Integer> list) { this.list = list; } public List<B> getbList() { return bList; } public void setbList(List<B> bList) { this.bList = bList; } @Override public String toString() { return "A1{" + "a=" + a + ", list=" + list + ", bList=" + bList + ", b=" + b + '}'; } }
- 類(lèi)B
class B { String b; public String getB() { return b; } public void setB(String b) { this.b = b; } @Override public String toString() { return "B{" + "b='" + b + '\'' + '}'; } public B() { } public B(String b) { this.b = b; } }
測(cè)試main方法1
public static void main(String[] args) { A a = new A(); B b = new B(); b.setB("bbb"); List<Integer> list = new ArrayList<>(); list.add(100); list.add(200); List<B> bList = new ArrayList<>(); bList.add(new B("dd")); bList.add(new B("cc")); bList.add(new B("ee")); a.setA(1); a.setB(b); a.setList(list); a.setbList(bList); A1 a1 = new A1(); BeanUtils.copyProperties(a, a1); System.out.println(a1); }
結(jié)果::A1{a=1, list=[100, 200], bList=[B{b=‘dd’}, B{b=‘cc’}, B{b=‘ee’}], b=B{b=‘bbb’}}
測(cè)試main方法2
public static void main(String[] args) { A a = new A(); B b = new B(); b.setB("bbb"); List<Integer> list = new ArrayList<>(); list.add(100); list.add(200); List<B> bList = new ArrayList<>(); bList.add(new B("dd")); bList.add(new B("cc")); bList.add(new B("ee")); a.setA(1); a.setB(b); a.setList(list); a.setbList(bList); A1 a1 = new A1(); BeanUtils.copyProperties(a, a1); b.setB("aaa"); a.setA(2); list.clear(); list.add(666); list.add(777); bList.clear(); bList.add(new B("abc")); System.out.println(a1); }
結(jié)果:A1{a=1, list=[666, 777], bList=[B{b=‘abc’}], b=B{b=‘aaa’}}
結(jié)果分析
從以上的例子和結(jié)果來(lái)看,BeanUtils.copyProperties是淺拷貝。
- main方法1: 當(dāng)A和A1中的屬性名稱(chēng)相同時(shí),使用BeanUtils.copyProperties會(huì)將所有屬性進(jìn)行復(fù)制。從結(jié)果上來(lái)看,不管是基本數(shù)據(jù)類(lèi)型
int a
,還是剩余的三個(gè)引用數(shù)據(jù)類(lèi)型,List<Integer> list
、List<B> bList
、B b
,都進(jìn)行了復(fù)制。 - main方法2 :第二個(gè)main方法在第一個(gè)的基礎(chǔ)上對(duì)要復(fù)制的A的屬性進(jìn)行了修改,從結(jié)果上發(fā)現(xiàn),A1的屬性中基本數(shù)據(jù)類(lèi)型
int a
的值并沒(méi)有因?yàn)樾薷亩淖?,但引用?shù)據(jù)類(lèi)型List<Integer> list
、List<B> bList
、B b
的值會(huì)因?yàn)楦淖兞薃的屬性而改變。
附帶兩種對(duì)象屬性復(fù)制的方法
// 淺拷貝 a1 = JSONObject.parseObject(JSONObject.toJSONString(a), A1.class) // 深拷貝,其中SerializerFeature.DisableCircularReferenceDetect是為了解決JSON的$ref 引用 a1 = JSONObject.parseObject(JSONObject.toJSONString(a, SerializerFeature.DisableCircularReferenceDetect), A1.class); // 深拷貝 ObjectMapper objectMapper = new ObjectMapper(); a1 = objectMapper.readValue(JSONObject.toJSONString(a, SerializerFeature.DisableCircularReferenceDetect), A1.class);
結(jié)論
BeanUtils.copyProperties的拷貝是淺拷貝,對(duì)基本數(shù)據(jù)類(lèi)型進(jìn)行值傳遞的屬性復(fù)制,改變?cè)緮?shù)據(jù)類(lèi)型的值不會(huì)改變被復(fù)制的屬性結(jié)果;
對(duì)引用數(shù)據(jù)類(lèi)型進(jìn)行引用傳遞的屬性復(fù)制,只是復(fù)制了一個(gè)內(nèi)存地址過(guò)去,指向的還是同一個(gè)對(duì)象,并沒(méi)有新建對(duì)象,改變?cè)瓕?duì)象的值,被復(fù)制的屬性的值也會(huì)隨著變化。
相關(guān)文章
使用javax.validation.constraints對(duì)請(qǐng)求體進(jìn)行統(tǒng)一校驗(yàn)
這篇文章主要介紹了使用javax.validation.constraints對(duì)請(qǐng)求體進(jìn)行統(tǒng)一校驗(yàn)方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-07-07使用SpringBoot+AOP實(shí)現(xiàn)可插拔式日志的示例代碼
這篇文章主要介紹了使用SpringBoot+AOP實(shí)現(xiàn)可插拔式日志的示例代碼,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-07-07基于Java編寫(xiě)一個(gè)數(shù)據(jù)庫(kù)比較工具類(lèi)
這篇文章主要為大家詳細(xì)介紹了如何基于Java編寫(xiě)一個(gè)數(shù)據(jù)庫(kù)比較工具類(lèi),其中比較結(jié)果會(huì)以現(xiàn)數(shù)據(jù)庫(kù)的視角說(shuō)明,感興趣的小伙伴可以了解一下2023-07-07使用Java編寫(xiě)一個(gè)簡(jiǎn)單的Web的監(jiān)控系統(tǒng)
這篇文章主要介紹了使用Java編寫(xiě)一個(gè)簡(jiǎn)單的Web的監(jiān)控系統(tǒng)的例子,并且將重要信息轉(zhuǎn)為XML通過(guò)網(wǎng)頁(yè)前端顯示,非常之實(shí)用,需要的朋友可以參考下2015-11-11webservice實(shí)現(xiàn)springboot項(xiàng)目間接口調(diào)用與對(duì)象傳遞示例
本文主要介紹了webservice實(shí)現(xiàn)springboot項(xiàng)目間接口調(diào)用與對(duì)象傳遞示例,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2022-07-07Java Chassis3注冊(cè)中心分區(qū)隔離技術(shù)解密
這篇文章主要為大家介紹了Java Chassis3注冊(cè)中心分區(qū)隔離技術(shù)解密,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2024-01-01詳解spring cloud Feign使用中遇到的問(wèn)題總結(jié)
本篇文章主要介紹了詳解spring cloud Feign使用中遇到的問(wèn)題總結(jié),小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2018-01-01Java實(shí)現(xiàn)的對(duì)稱(chēng)加密算法AES定義與用法詳解
這篇文章主要介紹了Java實(shí)現(xiàn)的對(duì)稱(chēng)加密算法AES,結(jié)合實(shí)例形式分析了對(duì)稱(chēng)加密算法AES的定義、特點(diǎn)、用法及使用場(chǎng)景,需要的朋友可以參考下2018-04-04