日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > java >内容正文

java

java 防止拷贝_[改善Java代码]避免对象的浅拷贝

發布時間:2024/9/15 java 37 豆豆
生活随笔 收集整理的這篇文章主要介紹了 java 防止拷贝_[改善Java代码]避免对象的浅拷贝 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

建議43: 避免對象的淺拷貝

我們知道一個類實現了Cloneable接口就表示它具備了被拷貝的能力,如果再覆寫clone()方法就會完全具備拷貝能力。拷貝是在內存中進行的,所以在性能方面比直接通過new生成對象要快很多,特別是在大對象的生成上,這會使性能的提升非常顯著。但是對象拷貝也有一個比較容易忽略的問題:淺拷貝(Shadow Clone,也叫做影子拷貝)存在對象屬性拷貝不徹底的問題。我們來看這樣一段代碼:

1 public classClient {2 public static voidmain(String[] args) {3 //定義父親

4 Person f = new Person("父親");5 //定義大兒子

6 Person s1 = new Person("大兒子",f);7 //小兒子的信息是通過大兒子拷貝過來的

8 Person s2 =s1.clone();9 s2.setName("小兒子");10 System.out.println(s1.getName() +" 的父親是 " +s1.getFather().getName());11 System.out.println(s2.getName() +" 的父親是 " +s2.getFather().getName());12 }13 }14

15 class Person implementsCloneable{16 //姓名

17 privateString name;18 //父親

19 privatePerson father;20

21 publicPerson(String _name){22 name =_name;23 }24 publicPerson(String _name,Person _parent){25 name =_name;26 father =_parent;27 }28 /*name和parent的getter/setter方法省略*/

29

30 //拷貝的實現

31 @Override32 publicPerson clone(){33 Person p = null;34 try{35 p = (Person) super.clone();36 } catch(CloneNotSupportedException e) {37 e.printStackTrace();38 }39 returnp;40 }41 publicString getName() {42 returnname;43 }44 public voidsetName(String name) {45 this.name =name;46 }47 publicPerson getFather() {48 returnfather;49 }50 public voidsetFather(Person father) {51 this.father =father;52 }53 }

程序中,我們描述了這樣一個場景:一個父親,有兩個兒子,大小兒子同根同種,所以小兒子對象就通過拷貝大兒子對象來生成,運行輸出的結果如下:

大兒子 的父親是 父親

小兒子 的父親是 父親

這很正確,沒有問題。突然有一天,父親心血來潮想讓大兒子去認個干爹,也就是大兒子的父親名稱需要重新設置一下,代碼如下:

1 public static voidmain(String[] args) {2 //定義父親

3 Person f = new Person("父親");4 //定義大兒子

5 Person s1 = new Person("大兒子",f);6 //小兒子的信息是通過大兒子拷貝過來的

7 Person s2 =s1.clone();8 s2.setName("小兒子");9 //認干爹

10 s1.getFather().setName("干爹");11 System.out.println(s1.getName() +" 的父親是 " +s1.getFather().getName());12 System.out.println(s2.getName() +" 的父親是 " +s2.getFather().getName());13 }

上面僅僅修改了加粗字體部分,大兒子重新設置了父親名稱,我們期望的輸出是:將大兒子父親的名稱修改為干爹,小兒子的父親名稱保持不變。下面來檢查一下結果是否如此:

大兒子 的父親是 干爹

小兒子 的父親是 干爹

怎么回事,小兒子的父親也成了“干爹”?兩個兒子都沒有,豈不是要氣死“父親”了!出現這個問題的原因就在于clone方法,我們知道所有類都繼承自Object,Object提供了一個對象拷貝的默認方法,即上面代碼中的super.clone方法,但是該方法是有缺陷的,它提供的是一種淺拷貝方式,也就是說它并不會把對象的所有屬性全部拷貝一份,而是有選擇性的拷貝,它的拷貝規則如下:

(1)基本類型

如果變量是基本類型,則拷貝其值,比如int、float等。

(2)對象

如果變量是一個實例對象,則拷貝地址引用,也就是說此時新拷貝出的對象與原有對象共享該實例變量,不受訪問權限的限制。這在Java中是很瘋狂的,因為它突破了訪問權限的定義:一個private修飾的變量,竟然可以被兩個不同的實例對象訪問,這讓Java的訪問權限體系情何以堪!

(3)String字符串

這個比較特殊,拷貝的也是一個地址,是個引用,但是在修改時,它會從字符串池(String Pool)中重新生成新的字符串,原有的字符串對象保持不變,在此處我們可以認為String是一個基本類型。(有關字符串的知識詳見第4章。)

明白了這三個規則,上面的例子就很清晰了,小兒子對象是通過拷貝大兒子產生的,其父親都是同一個人,也就是同一個對象,大兒子修改了父親名稱,小兒子也就跟著修改了—于是,父親的兩個兒子都沒了!其實要更正也很簡單,clone方法的代碼如下:

publicPerson clone(){

Person p= null;try{

p= (Person) super.clone();

p.setFather(newPerson(p.getFather().getName()));

}catch(CloneNotSupportedException e) {

e.printStackTrace();

}returnp;

}

然后再運行,小兒子的父親就不會是“干爹”了。如此就實現了對象的深拷貝(Deep Clone),保證拷貝出來的對象自成一體,不受“母體”的影響,和new生成的對象沒有任何區別。

注意 淺拷貝只是Java提供的一種簡單拷貝機制,不便于直接使用。

總結

以上是生活随笔為你收集整理的java 防止拷贝_[改善Java代码]避免对象的浅拷贝的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。