青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

chenglong7997

java中clone()

 目錄 

預備知識 
為什么要clone 
Object的clone以及為什么如此實現 
如何clone 
對clone的態度 
其他的選擇 
和Serializable的比較 
性能 

預備知識 

為了理解java的clone,有必要先溫習以下的知識。 
java的類型,java的類型分為兩大類,一類為primitive,如int,另一類為引用類型,如String,Object等等。 
java引用類型的存儲,java的引用類型都是存儲在堆上的
public class B { int a; String b; public B(int a, String b) { super(); this.a = a; this.b = b; } }

對這樣一個引用類型的實例,我們可以推測,在堆上它的內存存儲形式(除去指向class的引用,鎖的管理等等內務事務所占內存),應該有一個int值表示a,以及一個引用,該引用指向b在堆上的存儲空間。 
 

為什么要clone 

恩,因為需要。廢話。 
有名的GoF設計模式里有一個模式為原型模式,用原型實例指定創建對象的種類,并且通過拷貝這些原型創建新的對象. 
簡單的說就是clone一個對象實例。使得clone出來的copy和原有的對象一模一樣。 

插一個簡單使用clone的例子,如果一個對象內部有可變對象實例的話,public API不應該直接返回該對象的引用,以防調用方的code改變該對象的內部狀態。這個時候可以返回該對象的clone。 

問題來了,什么叫一模一樣。 
一般來說,有 
x.clone() != x 
x.clone().getClass() == x.getClass() 
x.clone().equals(x) 
但是這些都不是強制的。 
我們需要什么樣的clone就搞出什么樣的clone好了。 
一般而言,我們要的clone應該是這樣的。copy和原型的內容一樣,但是又是彼此隔離的。即在clone之后,改變其中一個不影響另外一個。 


Object的clone以及為什么如此實現 

Object的clone的行為是最簡單的。以堆上的內存存儲解釋的話(不計內務內存),對一個對象a的clone就是在堆上分配一個和a在堆上所占存儲空間一樣大的一塊地方,然后把a的堆上內存的內容復制到這個新分配的內存空間上。 
看例子。 
class User { 	String name; 	int age; } class Account implements Cloneable { 	User user; 	long balance; 	@Override 	public Object clone() throws CloneNotSupportedException { 		return super.clone(); 	} }


		// user. 		User user = new User(); 		user.name = "user"; 		user.age = 20; 		// account. 		Account account = new Account(); 		account.user = user; 		account.balance = 10000; 		// copy. 		Account copy = (Account) account.clone(); 		// balance因為是primitive,所以copy和原型是相等且獨立的。 		Assert.assertEquals(copy.balance, account.balance); 		copy.balance = 20000; 		// 改變copy不影響原型。 		Assert.assertTrue(copy.balance != account.balance); 		// user因為是引用類型,所以copy和原型的引用是同一的。 		Assert.assertTrue(copy.user == account.user); 		copy.user.name = "newName"; 		// 改變的是同一個東西。 		Assert.assertEquals("newName", account.user.name);

 

恩,默認實現是幫了我們一些忙,但是不是全部。 
primitive的確做到了相等且隔離。 
引用類型僅僅是復制了一下引用,copy和原型引用的東西是一樣的。 
這個就是所謂的淺copy了。 
要實現深copy,即復制原型中對象的內存copy,而不僅僅是一個引用。只有自己動手了。 
等等,是不是所有的引用類型都需要深copy呢? 
不是! 
我們之所以要深copy,是因為默認的實現提供的淺copy不是隔離的,換言之,改變copy的東西,會影響到原型的內部。比如例子中,改變copy的user的name,影響了原型。 
如果我們要copy的類是不可變的呢,如String,沒有方法可以改變它的內部狀態呢。 
class User implements Cloneable { 	String name; 	int age; 	@Override 	public Object clone() throws CloneNotSupportedException { 		return super.clone(); 	} }

		// user. 		User user = new User(); 		user.name = "user"; 		user.age = 20; 		// copy 		User copy = (User) user.clone(); 		// age因為是primitive,所以copy和原型是相等且獨立的。 		Assert.assertEquals(copy.age, user.age); 		copy.age = 30; 		// 改變copy不影響原型。 		Assert.assertTrue(copy.age != user.age); 		// name因為是引用類型,所以copy和原型的引用是同一的。 		Assert.assertTrue(copy.name == user.name); 		// String為不可變類。沒有辦法可以通過對copy.name的字符串的操作改變這個字符串。 		// 改變引用新的對象不會影響原型。 		copy.name = "newname"; 		Assert.assertEquals("newname", copy.name); 		Assert.assertEquals("user", user.name);
可見,在考慮clone時,primitive和不可變對象類型是可以同等對待的。 

java為什么如此實現clone呢? 
也許有以下考慮。 
1 效率和簡單性,簡單的copy一個對象在堆上的的內存比遍歷一個對象網然后內存深copy明顯效率高并且簡單。 
2 不給別的類強加意義。如果A實現了Cloneable,同時有一個引用指向B,如果直接復制內存進行深copy的話,意味著B在意義上也是支持Clone的,但是這個是在使用B的A中做的,B甚至都不知道。破壞了B原有的接口。 
3 有可能破壞語義。如果A實現了Cloneable,同時有一個引用指向B,該B實現為單例模式,如果直接復制內存進行深copy的話,破壞了B的單例模式。 
4 方便且更靈活,如果A引用一個不可變對象,則內存deep copy是一種浪費。Shadow copy給了程序員更好的靈活性。 

如何clone 
clone三部曲。 
1 聲明實現Cloneable接口。 
2 調用super.clone拿到一個對象,如果父類的clone實現沒有問題的話,在該對象的內存存儲中,所有父類定義的field都已經clone好了,該類中的primitive和不可變類型引用也克隆好了,可變類型引用都是淺copy。 
3 把淺copy的引用指向原型對象新的克隆體。 
給個例子。 
class User implements Cloneable { 	String name; 	int age; 	@Override 	public User clone() throws CloneNotSupportedException { 		return (User) super.clone(); 	} } class Account implements Cloneable { 	User user; 	long balance; 	@Override 	public Account clone() throws CloneNotSupportedException { 		Account account = null; 		account = (Account) super.clone(); 		if (user != null) { 			account.user = user.clone(); 		} 		return account; 	} }


 

對clone的態度 

clone嘛,我覺得是個好東西,畢竟系統默認實現已經幫我們做了很多事情了。 
但是它也是有缺點的。 
1 手工維護clone的調用鏈。這個問題不大,程序員有責任做好。 
2 如果class的field是個final的可變類,就不行了。三部曲的第三步沒有辦法做了。 

考慮一個類對clone的態度,有如下幾種。 
1 公開支持:好吧,按照clone三部曲實現吧。前提是父類支持(公開或者默默)。 
2 默默支持:不實現Cloneable接口,但是在類里面有正確的protected的clone實現,這樣,該類不支持clone,但是它的子類如果想支持的話也不妨礙。 
3 不支持:好吧,為了明確該目的,提供一個拋CloneNotSupportedException 異常的protected的clone實現。 
4 看情況支持:該類內部可以保存其他類的實例,如果其他類支持則該類支持,如果其他類不支持,該類沒有辦法,只有不支持。 


其他的選擇 

可以用原型構造函數,或者靜態copy方法來手工制作一個對象的copy。 
好處是即使class的field為final,也不會影響該方法的使用。不好的地方是所有的primitive賦值都得自己維護。 


和Serializable的比較 

使用Serializable同樣可以做到對象的clone。但是: 
Cloneable本身就是為clone設計的,雖然有一些缺點,但是如果它可以clone的話無疑用它來做clone比較合適。如果不行的話用原型構造函數,或者靜態copy方法也可以。 

Serializable制作clone的話,添加了太多其它的東西,增加了復雜性。 
1 所有的相關的類都得支持Serializable。這個相比支持Cloneable只會工作量更大 
2 Serializable添加了更多的意義,除了提供一個方法用Serializable制作Clone,該類等于也添加了其它的public API,如果一個類實現了Serializable,等于它的2進制形式就已經是其API的一部分了,不便于該類以后內部的改動。 
3 當類用Serializable來實現clone時,用戶如果保存了一個老版本的對象2進制,該類升級,用戶用新版本的類反系列化該對象,再調用該對象用Serializable實現的clone。這里為了一個clone的方法又引入了類版本兼容性的問題。不劃算。 


性能 

不可否認,JVM越來越快了。 
但是系統默認的native實現還是挺快的。 
clone一個有100個元素的int數組,用系統默認的clone比靜態copy方法快2倍左右。 

posted on 2012-04-11 14:08 Snape 閱讀(277) 評論(0)  編輯 收藏 引用 所屬分類: Java

導航

<2025年9月>
31123456
78910111213
14151617181920
21222324252627
2829301234
567891011

統計

常用鏈接

留言簿

隨筆分類

隨筆檔案

文章分類

文章檔案

my

搜索

最新評論

閱讀排行榜

評論排行榜

青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            亚洲国产日日夜夜| 免费人成精品欧美精品| 最新中文字幕亚洲| 欧美福利影院| 一区二区成人精品 | 亚洲美女黄色| 99xxxx成人网| 国产亚洲精品aa午夜观看| 欧美在线一级va免费观看| 欧美一级电影久久| 亚洲三级网站| 亚洲一区国产精品| 狠狠综合久久av一区二区老牛| 欧美成人日本| 欧美视频亚洲视频| 久久久久久久久伊人| 欧美二区在线播放| 欧美一区二区高清| 久久久久久久综合| 亚洲深夜福利视频| 欧美中文在线免费| 日韩一级黄色av| 午夜精品av| 日韩午夜视频在线观看| 午夜视频久久久久久| 亚洲精品免费一区二区三区| 亚洲天堂成人在线视频| 在线播放国产一区中文字幕剧情欧美 | 欧美日韩国产高清视频| 欧美专区在线观看| 欧美激情中文字幕一区二区| 欧美一区二区三区四区在线观看地址 | 国产精品午夜国产小视频| 麻豆九一精品爱看视频在线观看免费| 欧美日韩福利在线观看| 久久久蜜桃精品| 国产精品福利在线| 欧美国产日韩在线| 国产午夜亚洲精品不卡| 亚洲精品在线一区二区| 精品动漫av| 亚洲综合第一| 亚洲一级影院| 欧美激情综合色| 欧美成人在线网站| 国模一区二区三区| 亚洲免费中文| 性做久久久久久久久| 欧美日韩精品免费看| 欧美激情1区2区3区| 有码中文亚洲精品| 欧美一级大片在线免费观看| 先锋影音网一区二区| 欧美系列电影免费观看| 亚洲毛片在线观看.| av成人动漫| 欧美日韩免费看| 91久久精品www人人做人人爽| 1024精品一区二区三区| 久久精品国产一区二区电影 | 99精品免费视频| 欧美va日韩va| 亚洲国产一区二区视频| 亚洲乱码一区二区| 欧美激情国产日韩| 亚洲欧洲在线一区| 妖精视频成人观看www| 欧美日韩精品在线| 日韩天天综合| 午夜精品一区二区在线观看| 国产精品嫩草影院一区二区| 亚洲私人影院| 久久精品国产欧美亚洲人人爽| 国产日韩一区| 卡一卡二国产精品| 亚洲国语精品自产拍在线观看| 日韩亚洲欧美一区| 欧美视频在线观看免费| 亚洲一区二区三区精品动漫| 欧美一区二区三区四区在线 | 亚洲精品一区中文| 欧美体内谢she精2性欧美| 亚洲午夜av| 久久永久免费| 99在线热播精品免费99热| 欧美色视频一区| 欧美一区二区三区免费在线看| 麻豆精品在线观看| 中文有码久久| 狠狠色狠狠色综合日日91app| 毛片一区二区三区| 99国产精品久久久久久久久久| 欧美在线高清| 亚洲美女诱惑| 国产手机视频一区二区| 久热精品视频在线免费观看| 夜夜爽www精品| 久久男女视频| 亚洲视频电影图片偷拍一区| 国产欧美日韩精品丝袜高跟鞋| 久久久精品视频成人| 日韩视频一区二区| 久久久久久久精| 亚洲私人黄色宅男| 影音先锋国产精品| 国产精品久久波多野结衣| 久久欧美中文字幕| 亚洲校园激情| 亚洲欧洲综合另类| 久久午夜电影网| 香蕉精品999视频一区二区| 亚洲高清在线精品| 国产亚洲亚洲| 欧美午夜a级限制福利片| 久久综合久久久久88| 亚洲一区二区三区四区五区黄| 亚洲丶国产丶欧美一区二区三区| 亚洲欧美日韩另类| 中文亚洲字幕| 亚洲精品一区二区三区四区高清| 国产亚洲激情视频在线| 欧美日韩情趣电影| 蜜乳av另类精品一区二区| 新狼窝色av性久久久久久| 日韩一级在线观看| 亚洲高清视频在线| 老司机凹凸av亚洲导航| 久久黄色网页| 欧美一区永久视频免费观看| 亚洲图中文字幕| 亚洲精品久久久久中文字幕欢迎你| 国产偷国产偷精品高清尤物| 欧美日韩亚洲一区三区| 欧美国产成人在线| 久久在线免费| 久久亚洲精品视频| 久久本道综合色狠狠五月| 亚洲资源av| 亚洲专区一区| 亚洲午夜一级| 亚洲自拍偷拍网址| 亚洲综合第一页| 欧美在线一区二区| 亚洲欧美国产精品桃花| 亚洲私人黄色宅男| 亚洲自拍另类| 久久精品91久久久久久再现| 欧美一乱一性一交一视频| 欧美一级久久久| 久久九九99视频| 欧美国产大片| 欧美日韩综合精品| 国产精品视频午夜| 国内精品久久久久影院 日本资源 国内精品久久久久伊人av | 欧美大片第1页| 亚洲人久久久| 在线视频欧美一区| 欧美诱惑福利视频| 久久―日本道色综合久久| 免费成人性网站| 亚洲欧美另类综合偷拍| 欧美一区二区三区视频| 老牛嫩草一区二区三区日本| 欧美a级片一区| 99re6这里只有精品视频在线观看| 一本一本久久| 久久aⅴ国产欧美74aaa| 牛牛国产精品| 国产精品久久久久久av福利软件 | 亚洲国产岛国毛片在线| av成人免费在线| 性欧美xxxx大乳国产app| 久久久久久一区| 欧美美女bb生活片| 国产精品永久在线| 91久久精品视频| 性欧美8khd高清极品| 免费毛片一区二区三区久久久| 亚洲国产成人91精品| 亚洲桃花岛网站| 麻豆精品91| 国产精品综合网站| 91久久午夜| 久久精品国产一区二区电影| 91久久国产综合久久91精品网站| 亚洲一级一区| 欧美精彩视频一区二区三区| 国产亚洲一区二区三区在线播放| 最新亚洲电影| 久久婷婷国产麻豆91天堂| 日韩亚洲在线观看| 玖玖综合伊人| 国模 一区 二区 三区| 亚洲在线一区二区三区| 欧美成人免费在线观看| 亚洲欧美综合一区| 欧美日韩一本到| 亚洲毛片在线观看.| 久久婷婷国产麻豆91天堂| 中文在线不卡视频|