日本不卡不码高清免费观看,久久国产精品久久w女人spa,黄色aa久久,三上悠亚国产精品一区二区三区

您的位置:首頁技術文章
文章詳情頁

深入了解Java對象的克隆

瀏覽:22日期:2022-08-26 16:44:42

今天要介紹一個概念,對象的克隆。本篇有一定難度,請先做好心理準備。看不懂的話可以多看兩遍,還是不懂的話,可以在下方留言,我會看情況進行修改和補充。

克隆,自然就是將對象重新復制一份,那為什么要用克隆呢?什么時候需要使用呢?先來看一個小栗子:

簡單起見,我們這里用的是Goods類的簡單版本。

public class Goods { private String title; private double price; public Goods(String aTitle, double aPrice){ title = aTitle; price = aPrice; } public void setPrice(double price) { this.price = price; } public void setTitle(String title) { this.title = title; }//用于打印輸出商品信息 public void print(){ System.out.println('Title:'+title+' Price:'+price); }}

然后我們來使用這個類。

public class GoodsTest { public static void main(String[] args){ Goods goodsA = new Goods('GoodsA',20); Goods goodsB = goodsA; System.out.println('Before Change:'); goodsA.print(); goodsB.print(); goodsB.setTitle('GoodsB'); goodsB.setPrice(50); System.out.println('After Change:'); goodsA.print(); goodsB.print(); }}

我們創建了一個Goods對象賦值給變量goodsA,然后又創建了一個Goods變量,并把goodsA賦值給它,先調用Goods的print方法輸出這兩個變量中的信息,然后調用Goods類中的setTitle和setPrice方法來修改goodsB中的對象內容,再輸出兩個變量中的信息,下面是輸出:

Before Change:Title:GoodsA Price:20.0Title:GoodsA Price:20.0After Change:Title:GoodsB Price:50.0Title:GoodsB Price:50.0

這里我們發現了靈異事,我們明明修改的是goodsB的內容,可是goodsA的內容也同樣發生了改變,這究竟是為什么呢?別心急,且聽我慢慢道來。

在Java語言中,數據類型分為值類型(基本數據類型)和引用類型,值類型包括int、double、byte、boolean、char等簡單數據類型,引用類型包括類、接口、數組等復雜類型。使用等號賦值都是進行值傳遞的,如將一個整數型變量賦值給另一個整數型變量,那么后者將存儲前者的值,也就是變量中的整數值,對于基本類型如int,double,char等是沒有問題的,但是對于對象,則又是另一回事了,這里的goodsA和goodsB都是Goods類對象的變量,但是它們并沒有存儲Goods類對象的內容,而是存儲了它的地址,也就相當于C++中的指針,如果對于指針不了解,那我就再舉個栗子好了。我們之前舉過一個栗子,把計算機比作是倉庫管理員,內存比作是倉庫,你要使用什么類型的變量,就需要先登記,然后管理員才會把東西給你,但如果是給你分配一座房子呢?這時候不是把房子搬起來放到登記簿粒,而是登記下房子的地址,這里的地址就是我們的類對象變量里記錄的內容,所以,當我們把一個類對象變量賦值給另一個類對象變量,如goodsB = goodsA時,實際上只是把A指向的對象地址賦值給了B,這樣B也同樣指向這個地址,所以這時候,goodsA和goodsB操作的是同一個對象。

所以,如果只是簡單的賦值的話,之后對于goodsA和goodsB的操作都將影響同一個對象,這顯然不是我們的本意。也許你還會問,直接再new一個對象不就好了,確實如此,但有時候,如果我們需要保存一個goodsA的副本,那就不僅僅要new一個對象,還需要進行一系列賦值操作才能將我們的新對象設置成跟goodsA對象一樣,而且Goods類越復雜,這個操作將會越繁瑣,另外使用clone方法還進行本地優化,效率上也會快很多,總而言之,就是簡單粗暴。

那如何使用克隆呢?這里我們就要介紹我們牛逼哄哄的Object類了,所有的類都是Object類的子類,雖然我們并沒有顯式聲明繼承關系,但所有類都難逃它的魔掌,它有兩個protected方法,其中一個就是clone方法。

下面我來展示一波正確的騷操作:

//要使用克隆方法需要實現Cloneable接口public class Goods implements Cloneable{ private String title; private double price; public Goods(String aTitle, double aPrice){ title = aTitle; price = aPrice; } public void setPrice(double price) { this.price = price; } public void setTitle(String title) { this.title = title; } public void print(){ System.out.println('Title:'+title+' Price:'+price); } //這里重載了接口的clone方法 @Override protected Object clone(){ Goods g = null;//這里是異常處理的語句塊,可以先不用了解,只要知道是這樣使用就好,之后的文章中會有詳細的介紹 try{ g = (Goods)super.clone(); }catch (CloneNotSupportedException e){ System.out.println(e.toString()); } return g; }}

其實修改的地方只有兩個,一個是定義類的時候實現了Cloneable接口,關于接口的知識在之后會有詳細說明,這里只要簡單理解為是一種規范就行了,然后我們重載了clone方法,并在里面調用了父類也就是(Object)的clone方法。可以看到我們并沒有new一個新的對象,而是使用父類的clone方法進行克隆,關于try catch的知識這里不做過多介紹,之后會有文章做詳細說明,這里只需要理解為try語句塊里是一個可能發生錯誤的代碼,catch會捕獲這種錯誤并進行處理。

接下來我們再使用這個類的克隆方法:

public class GoodsTest { public static void main(String[] args){ Goods goodsA = new Goods('GoodsA',20); Goods goodsB = (Goods)goodsA.clone(); System.out.println('Before Change:'); goodsA.print(); goodsB.print(); goodsB.setTitle('GoodsB'); goodsB.setPrice(50); System.out.println('After Change:'); goodsA.print(); goodsB.print(); }}

我們僅僅是把賦值改成了調用goodsA的clone方法并進行類型轉換。輸出如下:

Before Change:Title:GoodsA Price:20.0Title:GoodsA Price:20.0After Change:Title:GoodsA Price:20.0Title:GoodsB Price:50.0

看,這樣不就達到我們目的了嗎?是不是很簡單?

但是別高興的太早,關于克隆,還有一點內容需要介紹。

克隆分為淺克隆和深克隆。我們上面使用的只是淺克隆,那兩者有什么區別呢?這里再舉一個栗子,使用的是簡化版的Cart類:

public class Cart implements Cloneable{ //實例域 Goods goodsList = new Goods('',0);//簡單起見,這里只放了一個商品 double budget = 0.0;//預算 //構造函數 public Cart(double aBudget){ budget = aBudget; } //獲取預算 public double getBudget() { return budget; } //修改預算 public void setBudget(double aBudget) { budget = aBudget; } //這里只是簡單的將商品進行了賦值 public void addGoods(Goods goods){ goodsList = (Goods) goods.clone(); } //這是為了演示加上的代碼,僅僅將商品標題修改成新標題 public void changeGoodsTitle(String title){ goodsList.setTitle(title); } //打印商品信息 public void print(){ System.out.print('Cart內的預算信息:'+budget+' 商品信息:'); goodsList.print(); } //重載clone方法 @Override protected Object clone(){ Cart c = null; try{ c = (Cart)super.clone(); }catch (CloneNotSupportedException e ){ e.printStackTrace(); } return c; }}

這里將goodsList由數組改成了單個對象變量,僅僅用于演示方便,還增加了一個changeGoodsTitle方法,用于將商品的標題修改成另一個標題,接下來修改一下GoodsTest類:

public class GoodsTest { public static void main(String[] args){ Goods goodsA = new Goods('GoodsA',20);//新建一個商品對象 Cart cartA = new Cart(5000);//新建一個購物車對象 cartA.addGoods(goodsA);//添加商品 Cart cartB = (Cart) cartA.clone();//使用淺克隆 //輸出修改前信息 System.out.println('Before Change:'); cartA.print(); cartB.print(); //修改購物車A中的商品標題 cartA.changeGoodsTitle('NewTitle'); //重新輸出修改后的信息 System.out.println('After Change:'); cartA.print(); cartB.print(); }}

輸出信息:

Before Change:Cart內的預算信息:5000.0 商品信息:Title:GoodsA Price:20.0Cart內的預算信息:5000.0 商品信息:Title:GoodsA Price:20.0After Change:Cart內的預算信息:5000.0 商品信息:Title:NewTitle Price:20.0Cart內的預算信息:5000.0 商品信息:Title:NewTitle Price:20.0

我們發現,雖然我們調用的是cartA中的方法修改購物車A中的商品信息,但購物車B中的信息同樣被修改了,這是因為使用淺克隆模式的時候,成員變量如果是對象等復雜類型時,僅僅使用的是值拷貝,就跟我們之前介紹的那樣,所以cartB雖然是cartA的一個拷貝,但是它們的成員變量goodsList卻共用一個對象,這樣就藕斷絲連了,顯然不是我們想要的效果,這時候就需要使用深拷貝了,只需要將Cart類的clone方法修改一下即可:

@Override protected Object clone(){ Cart c = null; try{ c = (Cart)super.clone(); c.goodsList = (Goods) goodsList.clone();//僅僅添加了這段代碼,將商品對象也進行了克隆 }catch (CloneNotSupportedException e ){ e.printStackTrace(); } return c; }

 現在再來運行一下:

Before Change:Cart內的預算信息:5000.0 商品信息:Title:GoodsA Price:20.0Cart內的預算信息:5000.0 商品信息:Title:GoodsA Price:20.0After Change:Cart內的預算信息:5000.0 商品信息:Title:NewTitle Price:20.0Cart內的預算信息:5000.0 商品信息:Title:GoodsA Price:20.0

這樣就得到了我們想要的結果了。

這樣,對象的拷貝就講完了。

嗎?

哈哈哈哈,不要崩潰,并沒有,還有一種更復雜的情況,那就是當你的成員變量里也包含引用類型的時候,比如Cart類中有一個CartB類的成員變量,CartB類中同樣存在引用類型的成員變量,這時候,就存在多層克隆的問題了。這里再介紹一個騷操作,只需要了解即可,那就是序列化對象。操作如下:

import java.io.*;public class Cart implements Serializable{ //實例域 Goods goodsList = new Goods('',0);//簡單起見,這里只放了一個商品 double budget = 0.0;//預算 //構造函數 public Cart(double aBudget){ budget = aBudget; } //獲取預算 public double getBudget() { return budget; } //修改預算 public void setBudget(double aBudget) { budget = aBudget; } //這里只是簡單的將商品進行了賦值 public void addGoods(Goods goods){ goodsList = (Goods) goods.clone(); } //這是為了演示加上的代碼,僅僅將商品標題修改成新標題 public void changeGoodsTitle(String title){ goodsList.setTitle(title); } //打印商品信息 public void print(){ System.out.print('Cart內的預算信息:'+budget+' 商品信息:'); goodsList.print(); }//這里是主要是騷操作 public Object deepClone() throws IOException, OptionalDataException,ClassNotFoundException { // 將對象寫到流里 ByteArrayOutputStream bo = new ByteArrayOutputStream(); ObjectOutputStream oo = new ObjectOutputStream(bo); oo.writeObject(this); // 從流里讀出來 ByteArrayInputStream bi = new ByteArrayInputStream(bo.toByteArray()); ObjectInputStream oi = new ObjectInputStream(bi); return (oi.readObject()); }}

關于這種方法我就不多做介紹了,大家只需要知道有這樣一種方法就行了,以后如果遇到了需要使用這種情況,就知道該怎樣處理了。

這里總結一下,對象的克隆就是把一個對象的當前狀態重新拷貝一份到另一個新對象中,兩個對象變量指向不同的對象,淺克隆僅僅調用super.clone()方法,對成員變量也只是簡單的值拷貝,所以當成員變量中有數組,對象等復雜類型的時候,就會存在藕斷絲連的混亂關系,深拷貝不僅僅調用super.clone()方法進行對象拷貝,將對象中的復雜類型同樣進行了拷貝,這樣兩個對象就再無瓜葛,井水不犯河水了。

至此,對象的克隆就真正的結束了,歡迎大家繼續關注!如有不懂的問題可以留言。也歡迎各位大佬來批評指正。喜歡我的教程的話記得動動小手點下推薦,也歡迎關注我的博客。

以上就是深入了解Java對象的克隆的詳細內容,更多關于Java 克隆的資料請關注好吧啦網其它相關文章!

標簽: Java
相關文章:
日本不卡不码高清免费观看,久久国产精品久久w女人spa,黄色aa久久,三上悠亚国产精品一区二区三区
成人av动漫在线观看| 欧美精品激情| 日韩国产欧美| 久久伦理在线| 亚洲精品第一| 你懂的国产精品| 99视频精品全部免费在线视频| 亚洲视频播放| 美女久久久久久| 午夜日韩福利| 国产麻豆精品| av在线日韩| 亚洲狼人精品一区二区三区| 久久久亚洲欧洲日产| 欧美sss在线视频| 日韩中文字幕麻豆| 欧美国产精品| 免费国产自久久久久三四区久久 | 先锋亚洲精品| 精品一区二区三区视频在线播放| 欧美/亚洲一区| 国产日产精品_国产精品毛片| 国产精品亚洲一区二区三区在线观看| 日韩精品亚洲一区二区三区免费| 精品资源在线| 视频一区欧美日韩| 日韩欧美网址| 欧美日韩视频免费看| 日本国产精品| 国产精品久久久久久久久久齐齐 | 日韩精品中文字幕一区二区| 91亚洲精品在看在线观看高清| 亚洲精品观看| 午夜在线视频观看日韩17c| 亚洲精品精选| 欧美激情日韩| 久久人人99| 日本久久二区| 97精品国产福利一区二区三区| 蜜臀久久99精品久久一区二区| 亚洲欧洲日韩| 欧美国产另类| 国产精品片aa在线观看| 老牛影视精品| 欧美国产另类| 日韩精品国产欧美| 午夜av一区| 亚洲国产专区| 午夜av一区| 免费在线日韩av| 樱桃成人精品视频在线播放| 欧美日韩夜夜| 欧美 日韩 国产精品免费观看| 亚洲精品电影| 国产欧美自拍| 日韩精品视频网| 日韩影院精彩在线| 另类欧美日韩国产在线| 97久久超碰| 蜜臀a∨国产成人精品| 欧美成人基地 | 久久网站免费观看| 韩日一区二区| 国产极品一区| 欧美日韩夜夜| 日韩精品午夜视频| 美女精品网站| 欧美特黄视频| 亚洲调教视频在线观看| 9999国产精品| 高清精品久久| 麻豆精品一区二区综合av| 亚洲精品系列| 视频在线观看91| 亚洲一区不卡| 99日韩精品| 激情欧美国产欧美| 麻豆国产91在线播放| 久久人人97超碰国产公开结果| 欧美日韩在线二区| 日韩欧美美女在线观看| 另类专区亚洲| 国产亚洲人成a在线v网站| 国产精品videossex久久发布 | 激情综合自拍| 日韩黄色在线观看| 激情偷拍久久| av资源新版天堂在线| 国产精品白丝久久av网站| 日韩一区网站| 日韩在线观看一区二区| 久久免费黄色| av最新在线| 久久精品二区亚洲w码| 国产欧美自拍一区| 四虎在线精品| 麻豆亚洲精品| 国户精品久久久久久久久久久不卡| 久久久久免费| 国产一区精品福利| 国产精品99久久久久久董美香| 亚洲ab电影| 亚洲精品乱码日韩| 美女91精品| 亚洲欧美成人综合| 亚洲精品a级片| 久久中文字幕二区| 日本蜜桃在线观看视频| 国产一区二区三区不卡av | 日本一区二区中文字幕| 日韩影院在线观看| 男女激情视频一区| 亚洲色图国产| 亚洲乱码视频| 日韩精品一二区| 亚洲中字黄色| 男人操女人的视频在线观看欧美| 亚洲欧美日韩视频二区| 亚洲一区二区网站| 丝袜美腿亚洲一区| 午夜在线视频观看日韩17c| 99pao成人国产永久免费视频 | 91成人精品在线| 青青草视频一区| 国产欧美一区二区三区国产幕精品| 视频一区欧美精品| 亚洲香蕉久久| 亚洲一区二区三区中文字幕在线观看| 亚洲激情社区| 综合国产视频| 欧美三区不卡| 国产一区国产二区国产三区| 香蕉久久久久久久av网站| 香蕉久久夜色精品国产| 国产精品网址| 国产综合精品| 欧美日韩一区自拍| 久久久久中文| 欧美日韩夜夜| 久久激情婷婷| 日韩影院免费视频| 免费亚洲一区| 欧美特黄视频| 国产精品传媒麻豆hd| 国产一区日韩欧美| 久久国产尿小便嘘嘘| 久久精品国产亚洲夜色av网站| 亚洲精品麻豆| 日韩大片在线播放| 日韩中文字幕| 日韩三区免费| 欧美日韩国产一区二区在线观看| 久久三级福利| 欧美视频久久| 欧洲毛片在线视频免费观看| 日本在线一区二区三区| 日本综合字幕| 国产午夜精品一区在线观看| 久久中文亚洲字幕| 欧美激情在线精品一区二区三区| 午夜精品影院| 精品一区二区三区免费看| 首页欧美精品中文字幕| 国产传媒av在线| 日韩av不卡一区二区| 欧美精品自拍| 久草免费在线视频| 国产日本精品| 三级亚洲高清视频| 99久久婷婷| 久久国产免费看| 国产模特精品视频久久久久| 国产一区二区久久久久| 亚洲影院天堂中文av色| 色老板在线视频一区二区| 国产图片一区| 日韩中文字幕av电影| 亚洲成a人片| 美女视频黄免费的久久| 久久亚洲国产精品一区二区| 欧美成a人国产精品高清乱码在线观看片在线观看久 | 亚洲精品在线a| 激情偷拍久久| 波多视频一区| 卡一精品卡二卡三网站乱码| 天堂va在线高清一区| 欧美~级网站不卡| 国产精品二区不卡| 国产精品羞羞答答在线观看| 免费欧美在线视频| 欧美aa在线观看| 国产一区调教| 国产精品久久国产愉拍| 色狠狠一区二区三区| 国产亚洲一区在线| 久久久亚洲一区| 日韩欧美看国产| 精品国产精品久久一区免费式| 日本不卡高清| 免费视频最近日韩|