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

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程语言 > java >内容正文

java

原型模式(ProtoType) - Java里的对象复制

發(fā)布時(shí)間:2025/3/20 java 14 豆豆
生活随笔 收集整理的這篇文章主要介紹了 原型模式(ProtoType) - Java里的对象复制 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.


一, 引用的復(fù)制和對(duì)象復(fù)制.

在編程中, 我們有時(shí)會(huì)用兩個(gè)引用指向同一個(gè)對(duì)象.


例如:

ArrayList a = new ArrayLIst(); ArrayList b = a;
看起來(lái)好像有a,b兩個(gè)容器, 實(shí)際上a,b是兩個(gè)引用, 它們都指向同1個(gè)Object的內(nèi)存地址.


而對(duì)象復(fù)制是指:

在內(nèi)存里劃分一塊與指定對(duì)象相同內(nèi)容的內(nèi)存.


也就是說(shuō)內(nèi)存里原理有1個(gè)Object的內(nèi)存, 復(fù)制后就有兩個(gè)了...




二, 對(duì)象復(fù)制的簡(jiǎn)便方法.

當(dāng)然, 對(duì)象復(fù)制的實(shí)現(xiàn)十分簡(jiǎn)單, 只需要實(shí)例化1個(gè)具有相同屬性的對(duì)象就ok了.

注意, 如果用 "==" 來(lái)講比較兩個(gè)引用是返回false, 因?yàn)樗鼈兊牡刂凡煌?


舉個(gè)列子:

2.1 產(chǎn)品類Prod:

public class Prod {private int prodID;private String prodName;public int getProdID() {return prodID;}public void setProdID(int prodID) {this.prodID = prodID;}public String getProdName() {return prodName;}public void setProdName(String prodName) {this.prodName = prodName;}@Overridepublic String toString(){return "Prod: " + this.getProdID() + " , " + this.getProdName();} }

2.2 訂單類Order:

public class Order {private int orderID;private Prod prod;private int amount;public int getOrderID() {return orderID;}public void setOrderID(int orderID) {this.orderID = orderID;}public Prod getProd() {return prod;}public void setProd(Prod prod) {this.prod = prod;}public int getAmount() {return amount;}public void setAmount(int amount) {this.amount = amount;}public String toString(){return "Order: " + this.getOrderID() + " , " + this.getAmount() + " " + this.getProd().toString();} }

2.3 客戶端代碼:

這里我先實(shí)例化1個(gè)order類 od1, 然后在復(fù)制1個(gè)od1 的對(duì)象od2

Prod p1 = new Prod();p1.setProdID(1);p1.setProdName("Hammer");Order od1 = new Order();od1.setOrderID(1);od1.setProd(p1);od1.setAmount(20);Prod p2 = new Prod();p2.setProdID(1);p2.setProdName("Hammer");Order od2 = new Order();od2.setOrderID(1);od2.setProd(p1);od2.setAmount(20);System.out.println(od1);System.out.println(od2);

輸出:

Order: 1 , 20 Prod: 1 , Hammer Order: 1 , 20 Prod: 1 , Hammer


2.4 這種方法的缺點(diǎn)

首先這種寫法不夠優(yōu)雅, 很多重復(fù)代碼.


其次, 這種復(fù)制方法調(diào)用了類的構(gòu)造函數(shù).

就如上面的例子, 即使Order類的構(gòu)造函數(shù)是空的, 但是實(shí)際上構(gòu)造函數(shù)的執(zhí)行機(jī)制很復(fù)雜,.

構(gòu)造函數(shù)最重要的動(dòng)作就是給類里的每個(gè)成員劃分內(nèi)存空間. 畢竟java是類c語(yǔ)言, 相當(dāng)于執(zhí)行了很多次malloc()函數(shù).


如果某些業(yè)務(wù)類的構(gòu)造函數(shù)寫的很復(fù)雜, 就更耗費(fèi)資源了.

而且



三, 利用Object.clone()方法來(lái)實(shí)現(xiàn)對(duì)象復(fù)制.


java里所有對(duì)象都是直接或簡(jiǎn)直繼承自基類Object.

而clone()是基類的Native 方法, 所謂Native方法可以認(rèn)為是java 內(nèi)部特定方法, 它比非Native的執(zhí)行效率要好.



也就是說(shuō), 利用Object.clone() 方法會(huì)比實(shí)例化1個(gè)相同內(nèi)容對(duì)象效率要好.


3.1 Object.clone()方法和 Cloneable接口:

Object.clone() 方法有點(diǎn)特殊,? 首先它是public方法, 也就是說(shuō)它可以通過(guò)引用名和"."來(lái)調(diào)用.

但是它不能被子類繼承, 也就說(shuō), 出了Object類外所有java里的class里面都沒有clone()這個(gè)方法的.


如果要使用Object.clone()方法.

只能引用1個(gè)叫做 Cloneable里的Interface,? 然后重寫Cloneable接口里的clone()方法, 在里面調(diào)用object.clone().


這個(gè)接口就起了1個(gè)標(biāo)記的作用, 幫組實(shí)現(xiàn)多態(tài).



3.2 訂單類Order:

我們按在這個(gè)思路來(lái)修改上面的訂單類Order:

public class Order implements Cloneable{private int orderID;private Prod prod;private int amount;public int getOrderID() {return orderID;}public void setOrderID(int orderID) {this.orderID = orderID;}public Prod getProd() {return prod;}public void setProd(Prod prod) {this.prod = prod;}public int getAmount() {return amount;}public void setAmount(int amount) {this.amount = amount;}public String toString(){return "Order: " + this.getOrderID() + " , " + this.getAmount() + " " + this.getProd().toString();}@Overridepublic Object clone(){Object o = null;try{o = super.clone();}catch(Exception e){e.printStackTrace();}return o;} }

值得注意的是, Object.clone() 回拋異常.

而, Prod類沒有任何修改.


3.3 客戶端代碼:

Prod p1 = new Prod();p1.setProdID(2);p1.setProdName("knife");Order od1 = new Order();od1.setOrderID(2);od1.setAmount(30);od1.setProd(p1);Order od2 = (Order)od1.clone();System.out.println(od1);System.out.println(od2);

可見, 只需要執(zhí)行一句 Order od2 = (Order)od1.clone();

就相當(dāng)于 復(fù)制了1個(gè)對(duì)象.


3.4 UML圖

我們來(lái)看看這個(gè)例子的UML:


實(shí)際上這個(gè)就是原型模式(prototype)的UML圖了,

原來(lái)我們不知不覺得使用了原型模式.



四, 原型模式的定義


原型模式(protoType), 用原型實(shí)例制定創(chuàng)建對(duì)象的種類, 并且通過(guò)copy這些原型創(chuàng)建新的對(duì)象.


總覺得設(shè)計(jì)模式的定義都太過(guò)于簡(jiǎn)單惡心了.


上面的

原型指的是? Cloneable這個(gè)接口.

原型實(shí)例指的是 Order這個(gè)類.



五, 淺復(fù)制和深復(fù)制

對(duì)象復(fù)制也分兩種.


淺復(fù)制:

?????????? 兩個(gè)對(duì)象中的值類型成員屬性相等,? 對(duì)象成員成員屬性實(shí)際上沒有復(fù)制,都是同一個(gè)對(duì)象.


深復(fù)制:

????????? 兩個(gè)對(duì)象中的值類型成員屬性相等,? 對(duì)象成員屬性指向不同的 具有相同成員的 對(duì)象.



如上面的例子, 稍稍修改客戶端代碼:

Prod p1 = new Prod();p1.setProdID(2);p1.setProdName("knife");Order od1 = new Order();od1.setOrderID(2);od1.setAmount(30);od1.setProd(p1);Order od2 = (Order)od1.clone();System.out.println(od1);System.out.println(od2);od1.setOrderID(3);od1.setAmount(40);od1.getProd().setProdName("blade");System.out.println(od1);System.out.println(od2);

上面 構(gòu)建了對(duì)象od1,

然后復(fù)制出了另1個(gè)對(duì)象od2,


然后修改od1的 值成員 和 對(duì)象成員

然后輸出od1, 和 od2 成員的值:

Order: 2 , 30 Prod: 2 , knife Order: 2 , 30 Prod: 2 , knife Order: 3 , 40 Prod: 2 , blade Order: 2 , 30 Prod: 2 , blade

可見, 當(dāng)od1 的id 和 amount的值被改成 3 和 40 后,? od2 的id和 Amount的值并不受影響, 因?yàn)樗鼈兊闹殿愋统蓡T屬性是相互獨(dú)立的.

但是當(dāng)od1 的 prod屬性的內(nèi)容被修改后,??? od2 的也被修改了(knife - > blade),? 因?yàn)?od1 和 od2 的 prod成員指向的都是同1個(gè)對(duì)象.


這就證明了:

Java里的 Object.clone()方法實(shí)現(xiàn)的是淺復(fù)制.


六, 原型模式的深復(fù)制實(shí)現(xiàn)

接下來(lái)再次修改上面的例子, 令其實(shí)現(xiàn)成深復(fù)制

而且, 根據(jù)項(xiàng)目需要, 復(fù)制并不會(huì)復(fù)制Order的id, 也就是訂單號(hào)碼是唯一的, 只復(fù)制Prod和數(shù)量.


6.1 訂單類Order:

public class Order implements Cloneable{private int orderID;private Prod prod;private int amount;public int getOrderID() {return orderID;}public void setOrderID(int orderID) {this.orderID = orderID;}public Prod getProd() {return prod;}public void setProd(Prod prod) {this.prod = prod;}public int getAmount() {return amount;}public void setAmount(int amount) {this.amount = amount;}public String toString(){return "Order: " + this.getOrderID() + " , " + this.getAmount() + " " + this.getProd().toString();}@Overridepublic Object clone(){Prod p = new Prod();p.setProdID(this.getProd().getProdID());p.setProdName(this.getProd().getProdName());Order o = new Order();o.setOrderID(this.getOrderID() + 1);o.setAmount(this.getAmount());o.setProd(p);return o;} }

客戶端輸出:

Order: 2 , 30 Prod: 2 , knife Order: 3 , 30 Prod: 2 , knife Order: 3 , 40 Prod: 2 , blade Order: 3 , 30 Prod: 2 , knife

可以, 無(wú)論od1修改了什么,? od2 都不受影響


這種方法放棄了Object.clone(), Order類在重寫clone()方法里還是使用了構(gòu)造方法去實(shí)例化1個(gè)新的對(duì)象.


這種方法配置更加靈活(選擇性地復(fù)制成員)

當(dāng)時(shí)放棄了Object.clone()的效能優(yōu)點(diǎn).

但是這仍然實(shí)現(xiàn)了原型模式(protoType)

























總結(jié)

以上是生活随笔為你收集整理的原型模式(ProtoType) - Java里的对象复制的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。