JAVA對(duì)象深拷貝和淺拷貝

1烂斋、什么是深拷貝屹逛、什么是淺拷貝

淺拷貝:淺拷貝不會(huì)生成新的對(duì)象,只會(huì)在原對(duì)象上增加了一個(gè)新的對(duì)象引用汛骂,兩個(gè)引用指向的對(duì)象是同一個(gè)罕模;



深拷貝:深拷貝是重新生成一個(gè)新的對(duì)象,然后把原來(lái)對(duì)象的值拷貝到新對(duì)象的一個(gè)過(guò)程帘瞭,新的對(duì)象和原來(lái)的對(duì)象是沒(méi)有任何關(guān)系的手销。



2、淺拷貝場(chǎng)景:

java 對(duì)象默認(rèn)的對(duì)象拷貝方式都為淺拷貝图张,下面我們來(lái)看一下我們程序里面常見(jiàn)的例子:

(1)首先定義一個(gè)User類(lèi)

public classUser {private int age;//年齡privateStringname;//姓名public intgetAge() {return age;

}public voidsetAge(intage) {this.age= age;

}publicString getName() {return name;

}public voidsetName(String name) {this.name= name;

}

@OverridepublicString toString() {return "User{"+"age="+age+", name='"+name+'\''+'}';

}

}

(2)測(cè)試代碼:

public static voidmain(String[] args) {//1锋拖、實(shí)例化一個(gè)user1對(duì)象,并對(duì)屬性賦值User user1=newUser();

user1.setName("我是user1");

user1.setAge(18);//2祸轮、把user1對(duì)象放到一個(gè)List里面List userList=newArrayList();

userList.add(user1);//3兽埃、然后創(chuàng)建user2 對(duì)象并從List里面拿出user1對(duì)象賦值給user2User user2= userList.get(0);//4、給user2的屬性值user2.setAge(1);

user2.setName("我是user2");//5适袜、這個(gè)的時(shí)候我們?cè)佥敵鰑ser1的對(duì)應(yīng)屬性值System.out.println(user1);

}

最后我們看看打印結(jié)果:



舉了一個(gè)比較繞的例子是想更好的提現(xiàn)出淺拷貝可能會(huì)給我們帶來(lái)的問(wèn)題柄错;

結(jié)合淺拷貝的圖解我想我們不難理解這個(gè)結(jié)果是怎么出現(xiàn)的,因?yàn)閡ser1和user2其實(shí)指向的是同一個(gè)對(duì)象,所以當(dāng)我們修改user2的屬性時(shí)其實(shí)修改的也是user1這個(gè)對(duì)象苦酱。

程序中如果像這種在一個(gè)對(duì)象上多次淺拷貝并使用其實(shí)是很危險(xiǎn)的售貌,有時(shí)候調(diào)用的層次多了被傳遞的使用者修改了對(duì)象屬性會(huì)造成業(yè)務(wù)邏輯上的錯(cuò)誤(想想上面的例子,如果在user2修改屬性值之后疫萤,還有業(yè)務(wù)代碼要拿user1來(lái)進(jìn)行業(yè)務(wù)操作的話(huà)颂跨,那么此時(shí)的user1屬性值都已經(jīng)被修改了,這樣勢(shì)必會(huì)產(chǎn)生業(yè)務(wù)上的錯(cuò)誤)扯饶,而這樣的問(wèn)題又比較難發(fā)現(xiàn)恒削,并且這樣也會(huì)造成代碼的理解成本變高,可讀性也會(huì)變差尾序。

總結(jié):因?yàn)闇\拷貝的特性我們要盡少對(duì)淺拷貝的對(duì)象進(jìn)行屬性值的修改钓丰,如果有需要拷貝對(duì)象的時(shí)候,我們可以考慮用對(duì)象克隆的方式來(lái)把對(duì)象進(jìn)行深度拷貝每币。

3携丁、如何對(duì)對(duì)象進(jìn)行深度拷貝

方式一:實(shí)現(xiàn)Cloneable接口

(1)需要拷貝的對(duì)象實(shí)現(xiàn)Cloneable 接口

public classUserimplementsCloneable {privateStringname;privateIntegerage;publicString getName() {return name;

}public voidsetName(String name) {this.name= name;

}publicInteger getAge() {return age;

}public voidsetAge(Integer age) {this.age= age;

}

@OverrideprotectedObject clone()throwsCloneNotSupportedException {return super.clone();

}

@OverridepublicString toString() {return "User{"+"name='"+name+'\''+", age="+age+'}';

}

}

(2)然后我們按上面的流程測(cè)試

public static voidmain(String[] args) {try{

User user1 =newUser();

user1.setName("我是user11");

user1.setAge(188);

List userList =newArrayList();

userList.add(user1);//克隆user1對(duì)象User user2 = (User) userList.get(0).clone();

user2.setAge(11);

user2.setName("我是user22");

System.out.println(user1);

System.out.println(user2);

}catch(Exception e) {

e.printStackTrace();

}

}

(3)打印結(jié)果



注意: 如果User 里有一個(gè)Class 對(duì)象的屬性,此時(shí)需要完全深度克隆的話(huà)兰怠,那么Class這個(gè)類(lèi)也要實(shí)現(xiàn)Cloneable 接口梦鉴,否則只有user其他的屬性值深度拷貝了李茫,但class這個(gè)對(duì)象還是進(jìn)行淺拷貝;



方式二:把對(duì)象進(jìn)行序列化后再反序列化

(1)對(duì)象實(shí)現(xiàn)序列化接口

public classUserimplementsSerializable{privateStringname;privateIntegerage;publicString getName() {return name;

}public voidsetName(String name) {this.name= name;

}publicInteger getAge() {return age;

}public voidsetAge(Integer age) {this.age= age;

}

@OverridepublicString toString() {return "User{"+"name='"+name+'\''+", age="+age+'}';

}

}

(1)把對(duì)象進(jìn)行序列化后再反序列化

public static voidmain(String[] args) {try{

User user1 =newUser();

user1.setName("我是user111");

user1.setAge(1888);//序列化寫(xiě)入到流里ByteOutputStream bots=newByteOutputStream();

ObjectOutputStream oos =newObjectOutputStream(bots);

oos.writeObject(user1);//反序列化成user2對(duì)象ObjectInputStream ois=newObjectInputStream(newByteArrayInputStream(bots.toByteArray()));

User user2 = (User) ois.readObject();

user2.setAge(111);

user2.setName("我是user222");

System.out.println(user1);

System.out.println(user2);

}catch(Exception e) {

e.printStackTrace();

}

}

最后看結(jié)果:



4尚揣、最后找了一個(gè)深度拷貝工具類(lèi)供大家使用

public abstract classBeanUtil {public static T cloneTo(T src)throwsRuntimeException {

ByteArrayOutputStream memoryBuffer =newByteArrayOutputStream();

ObjectOutputStream out =null;

ObjectInputStream in =null;

T dist =null;try{

out =newObjectOutputStream(memoryBuffer);

out.writeObject(src);

out.flush();

in =newObjectInputStream(newByteArrayInputStream(memoryBuffer.toByteArray()));

dist = (T) in.readObject();

}catch(Exception e) {throw newRuntimeException(e);

}finally{if(out !=null) {try{

out.close();

out =null;

}catch(IOException e) {throw newRuntimeException(e);

}

}if(in !=null) {try{

in.close();

in =null;

}catch(IOException e) {throw newRuntimeException(e);

}

}

}returndist;

}

}

,

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末涌矢,一起剝皮案震驚了整個(gè)濱河市掖举,隨后出現(xiàn)的幾起案子快骗,更是在濱河造成了極大的恐慌,老刑警劉巖塔次,帶你破解...
    沈念sama閱讀 222,104評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件方篮,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡励负,警方通過(guò)查閱死者的電腦和手機(jī)藕溅,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,816評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)继榆,“玉大人巾表,你說(shuō)我怎么就攤上這事÷远郑” “怎么了集币?”我有些...
    開(kāi)封第一講書(shū)人閱讀 168,697評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵,是天一觀(guān)的道長(zhǎng)翠忠。 經(jīng)常有香客問(wèn)我鞠苟,道長(zhǎng),這世上最難降的妖魔是什么秽之? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 59,836評(píng)論 1 298
  • 正文 為了忘掉前任当娱,我火速辦了婚禮,結(jié)果婚禮上考榨,老公的妹妹穿的比我還像新娘跨细。我一直安慰自己,他們只是感情好河质,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,851評(píng)論 6 397
  • 文/花漫 我一把揭開(kāi)白布扼鞋。 她就那樣靜靜地躺著,像睡著了一般愤诱。 火紅的嫁衣襯著肌膚如雪云头。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 52,441評(píng)論 1 310
  • 那天淫半,我揣著相機(jī)與錄音溃槐,去河邊找鬼。 笑死科吭,一個(gè)胖子當(dāng)著我的面吹牛昏滴,可吹牛的內(nèi)容都是我干的猴鲫。 我是一名探鬼主播,決...
    沈念sama閱讀 40,992評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼谣殊,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼拂共!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起姻几,我...
    開(kāi)封第一講書(shū)人閱讀 39,899評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤宜狐,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后蛇捌,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體抚恒,經(jīng)...
    沈念sama閱讀 46,457評(píng)論 1 318
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,529評(píng)論 3 341
  • 正文 我和宋清朗相戀三年络拌,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了俭驮。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,664評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡春贸,死狀恐怖混萝,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情萍恕,我是刑警寧澤逸嘀,帶...
    沈念sama閱讀 36,346評(píng)論 5 350
  • 正文 年R本政府宣布,位于F島的核電站雄坪,受9級(jí)特大地震影響厘熟,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜维哈,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,025評(píng)論 3 334
  • 文/蒙蒙 一绳姨、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧阔挠,春花似錦飘庄、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,511評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至迂求,卻和暖如春碾盐,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背揩局。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,611評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工毫玖, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 49,081評(píng)論 3 377
  • 正文 我出身青樓付枫,卻偏偏與公主長(zhǎng)得像烹玉,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子阐滩,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,675評(píng)論 2 359

推薦閱讀更多精彩內(nèi)容