电脑知识|欧美黑人一区二区三区|软件|欧美黑人一级爽快片淫片高清|系统|欧美黑人狂野猛交老妇|数据库|服务器|编程开发|网络运营|知识问答|技术教程文章 - 好吧啦网

您的位置:首頁(yè)技術(shù)文章
文章詳情頁(yè)

深入了解Java對(duì)象的克隆

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

今天要介紹一個(gè)概念,對(duì)象的克隆。本篇有一定難度,請(qǐng)先做好心理準(zhǔn)備。看不懂的話可以多看兩遍,還是不懂的話,可以在下方留言,我會(huì)看情況進(jìn)行修改和補(bǔ)充。

克隆,自然就是將對(duì)象重新復(fù)制一份,那為什么要用克隆呢?什么時(shí)候需要使用呢?先來(lái)看一個(gè)小栗子:

簡(jiǎn)單起見(jiàn),我們這里用的是Goods類的簡(jiǎn)單版本。

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); }}

然后我們來(lái)使用這個(gè)類。

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(); }}

我們創(chuàng)建了一個(gè)Goods對(duì)象賦值給變量goodsA,然后又創(chuàng)建了一個(gè)Goods變量,并把goodsA賦值給它,先調(diào)用Goods的print方法輸出這兩個(gè)變量中的信息,然后調(diào)用Goods類中的setTitle和setPrice方法來(lái)修改goodsB中的對(duì)象內(nèi)容,再輸出兩個(gè)變量中的信息,下面是輸出:

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

這里我們發(fā)現(xiàn)了靈異事,我們明明修改的是goodsB的內(nèi)容,可是goodsA的內(nèi)容也同樣發(fā)生了改變,這究竟是為什么呢?別心急,且聽(tīng)我慢慢道來(lái)。

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

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

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

下面我來(lái)展示一波正確的騷操作:

//要使用克隆方法需要實(shí)現(xiàn)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;//這里是異常處理的語(yǔ)句塊,可以先不用了解,只要知道是這樣使用就好,之后的文章中會(huì)有詳細(xì)的介紹 try{ g = (Goods)super.clone(); }catch (CloneNotSupportedException e){ System.out.println(e.toString()); } return g; }}

其實(shí)修改的地方只有兩個(gè),一個(gè)是定義類的時(shí)候?qū)崿F(xiàn)了Cloneable接口,關(guān)于接口的知識(shí)在之后會(huì)有詳細(xì)說(shuō)明,這里只要簡(jiǎn)單理解為是一種規(guī)范就行了,然后我們重載了clone方法,并在里面調(diào)用了父類也就是(Object)的clone方法。可以看到我們并沒(méi)有new一個(gè)新的對(duì)象,而是使用父類的clone方法進(jìn)行克隆,關(guān)于try catch的知識(shí)這里不做過(guò)多介紹,之后會(huì)有文章做詳細(xì)說(shuō)明,這里只需要理解為try語(yǔ)句塊里是一個(gè)可能發(fā)生錯(cuò)誤的代碼,catch會(huì)捕獲這種錯(cuò)誤并進(jìn)行處理。

接下來(lái)我們?cè)偈褂眠@個(gè)類的克隆方法:

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(); }}

我們僅僅是把賦值改成了調(diào)用goodsA的clone方法并進(jìn)行類型轉(zhuǎn)換。輸出如下:

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

看,這樣不就達(dá)到我們目的了嗎?是不是很簡(jiǎn)單?

但是別高興的太早,關(guān)于克隆,還有一點(diǎn)內(nèi)容需要介紹。

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

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

這里將goodsList由數(shù)組改成了單個(gè)對(duì)象變量,僅僅用于演示方便,還增加了一個(gè)changeGoodsTitle方法,用于將商品的標(biāo)題修改成另一個(gè)標(biāo)題,接下來(lái)修改一下GoodsTest類:

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

輸出信息:

Before Change:Cart內(nèi)的預(yù)算信息:5000.0 商品信息:Title:GoodsA Price:20.0Cart內(nèi)的預(yù)算信息:5000.0 商品信息:Title:GoodsA Price:20.0After Change:Cart內(nèi)的預(yù)算信息:5000.0 商品信息:Title:NewTitle Price:20.0Cart內(nèi)的預(yù)算信息:5000.0 商品信息:Title:NewTitle Price:20.0

我們發(fā)現(xiàn),雖然我們調(diào)用的是cartA中的方法修改購(gòu)物車A中的商品信息,但購(gòu)物車B中的信息同樣被修改了,這是因?yàn)槭褂脺\克隆模式的時(shí)候,成員變量如果是對(duì)象等復(fù)雜類型時(shí),僅僅使用的是值拷貝,就跟我們之前介紹的那樣,所以cartB雖然是cartA的一個(gè)拷貝,但是它們的成員變量goodsList卻共用一個(gè)對(duì)象,這樣就藕斷絲連了,顯然不是我們想要的效果,這時(shí)候就需要使用深拷貝了,只需要將Cart類的clone方法修改一下即可:

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

 現(xiàn)在再來(lái)運(yùn)行一下:

Before Change:Cart內(nèi)的預(yù)算信息:5000.0 商品信息:Title:GoodsA Price:20.0Cart內(nèi)的預(yù)算信息:5000.0 商品信息:Title:GoodsA Price:20.0After Change:Cart內(nèi)的預(yù)算信息:5000.0 商品信息:Title:NewTitle Price:20.0Cart內(nèi)的預(yù)算信息:5000.0 商品信息:Title:GoodsA Price:20.0

這樣就得到了我們想要的結(jié)果了。

這樣,對(duì)象的拷貝就講完了。

嗎?

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

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

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

這里總結(jié)一下,對(duì)象的克隆就是把一個(gè)對(duì)象的當(dāng)前狀態(tài)重新拷貝一份到另一個(gè)新對(duì)象中,兩個(gè)對(duì)象變量指向不同的對(duì)象,淺克隆僅僅調(diào)用super.clone()方法,對(duì)成員變量也只是簡(jiǎn)單的值拷貝,所以當(dāng)成員變量中有數(shù)組,對(duì)象等復(fù)雜類型的時(shí)候,就會(huì)存在藕斷絲連的混亂關(guān)系,深拷貝不僅僅調(diào)用super.clone()方法進(jìn)行對(duì)象拷貝,將對(duì)象中的復(fù)雜類型同樣進(jìn)行了拷貝,這樣兩個(gè)對(duì)象就再無(wú)瓜葛,井水不犯河水了。

至此,對(duì)象的克隆就真正的結(jié)束了,歡迎大家繼續(xù)關(guān)注!如有不懂的問(wèn)題可以留言。也歡迎各位大佬來(lái)批評(píng)指正。喜歡我的教程的話記得動(dòng)動(dòng)小手點(diǎn)下推薦,也歡迎關(guān)注我的博客。

以上就是深入了解Java對(duì)象的克隆的詳細(xì)內(nèi)容,更多關(guān)于Java 克隆的資料請(qǐng)關(guān)注好吧啦網(wǎng)其它相關(guān)文章!

標(biāo)簽: Java
相關(guān)文章:
主站蜘蛛池模板: 纸箱网 -纸箱机械|设备|包装纸盒|包装印刷行业门户网站 | 色谱柱-淋洗液罐-巴罗克试剂槽-巴氏吸管-5ml样品瓶-SBS液氮冻存管-上海希言科学仪器有限公司 | 电磁铁_小型推拉电磁铁_电磁阀厂家-深圳市宗泰电机有限公司 | 花纹铝板,合金铝卷板,阴极铝板-济南恒诚铝业有限公司 | 拼装地板,悬浮地板厂家,悬浮式拼装运动地板-石家庄博超地板科技有限公司 | 螺杆泵_中成泵业| 桂林腻子粉_内墙外墙抗裂砂浆腻子粉推荐广西鑫达涂料厂家供应 | 手板_手板模型制作_cnc手板加工厂-东莞天泓 | 洗地机_全自动洗地机_手推式洗地机【上海滢皓环保】 | 成都顶呱呱信息技术有限公司-贷款_个人贷款_银行贷款在线申请 - 成都贷款公司 | 沙盘模型公司_沙盘模型制作公司_建筑模型公司_工业机械模型制作厂家 | 河南砖机首页-全自动液压免烧砖机,小型砌块水泥砖机厂家[十年老厂] | 安徽控制器-合肥船用空调控制器-合肥家电控制器-合肥迅驰电子厂 安徽净化板_合肥岩棉板厂家_玻镁板厂家_安徽科艺美洁净科技有限公司 | 广东护栏厂家-广州护栏网厂家-广东省安麦斯交通设施有限公司 | 蓄电池回收,ups电池后备电源回收,铅酸蓄电池回收,机房电源回收-广州益夫铅酸电池回收公司 | 轻型地埋电缆故障测试仪,频响法绕组变形测试仪,静荷式卧式拉力试验机-扬州苏电 | 涂层测厚仪_光泽度仪_uv能量计_紫外辐照计_太阳膜测试仪_透光率仪-林上科技 | 提升海外网站流量,增加国外网站访客UV,定制海外IP-访客王 | 皮带输送机-大倾角皮带输送机-皮带输送机厂家-河南坤威机械 | 震动筛选机|震动分筛机|筛粉机|振筛机|振荡筛-振动筛分设备专业生产厂家高服机械 | 美甲贴片-指甲贴片-穿戴美甲-假指甲厂家--薇丝黛拉 | 转向助力泵/水泵/发电机皮带轮生产厂家-锦州华一精工有限公司 | 广东佛电电器有限公司|防雷开关|故障电弧断路器|智能量测断路器 广东西屋电气有限公司-广东西屋电气有限公司 | 四川职高信息网-初高中、大专、职业技术学校招生信息网 | 塑料熔指仪-塑料熔融指数仪-熔体流动速率试验机-广东宏拓仪器科技有限公司 | 西宁装修_西宁装修公司-西宁业之峰装饰-青海业之峰墅级装饰设计公司【官网】 | 风电变桨伺服驱动器-风电偏航变桨系统-深圳众城卓越科技有限公司 | 粉末冶金-粉末冶金齿轮-粉末冶金零件厂家-东莞市正朗精密金属零件有限公司 | 自清洗过滤器,浅层砂过滤器,叠片过滤器厂家-新乡市宇清净化 | 天一线缆邯郸有限公司_煤矿用电缆厂家_矿用光缆厂家_矿用控制电缆_矿用通信电缆-天一线缆邯郸有限公司 | 不锈钢复合板|钛复合板|金属复合板|南钢集团安徽金元素复合材料有限公司-官网 | 不锈钢散热器,冷却翅片管散热器厂家-无锡市烨晟化工装备科技有限公司 | 西宁装修_西宁装修公司-西宁业之峰装饰-青海业之峰墅级装饰设计公司【官网】 | 萃取箱-萃取槽-PVC萃取箱厂家-混合澄清槽- 杭州南方化工设备 | 滚筒线,链板线,总装线,流水线-上海体能机电有限公司 | 北京晚会活动策划|北京节目录制后期剪辑|北京演播厅出租租赁-北京龙视星光文化传媒有限公司 | 钢板仓,大型钢板仓,钢板库,大型钢板库,粉煤灰钢板仓,螺旋钢板仓,螺旋卷板仓,骨料钢板仓 | 上海电子秤厂家,电子秤厂家价格,上海吊秤厂家,吊秤供应价格-上海佳宜电子科技有限公司 | 辽宁资质代办_辽宁建筑资质办理_辽宁建筑资质延期升级_辽宁中杭资质代办 | 中国产业发展研究网 - 提供行业研究报告 可行性研究报告 投资咨询 市场调研服务 | 净化车间_洁净厂房_净化公司_净化厂房_无尘室工程_洁净工程装修|改造|施工-深圳净化公司 |