亚洲激情专区-91九色丨porny丨老师-久久久久久久女国产乱让韩-国产精品午夜小视频观看

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

什么是Java淺拷貝和深拷貝

發布時間:2021-10-29 15:23:59 來源:億速云 閱讀:129 作者:iii 欄目:web開發

這篇文章主要講解了“什么是Java淺拷貝和深拷貝”,文中的講解內容簡單清晰,易于學習與理解,下面請大家跟著小編的思路慢慢深入,一起來研究和學習“什么是Java淺拷貝和深拷貝”吧!

問題

“如果你有一個對象, 并希望生成與其完全相同的一個復制品, 你該如何實現呢?首先, 你必須新建一個屬于相同類的對象。然后,  你必須遍歷原始對象的所有成員變量, 并將成員變量值復制到新對象中。

for (int i = 0; i < 10; i++) {   Sheep sheep = new Sheep("肖恩"+i+"號",2+i,"白色");   System.out.println(sheep.toString()); }

這種方式是比較容易想到的,但是有幾個不足

  • 在創建新對象的時候,總是需要重新獲取原始對象的屬性,如果創建的對象比較復雜,效率會很低

  • 總是需要重新初始化對象,而不是動態地獲得對象運行時的狀態, 不夠靈活

  • 另一方面,并非所有對象都能通過這種方式進行復制, 因為有些對象可能擁有私有成員變量, 它們在對象本身以外是不可見的

“萬物兼對象的 Java 中的所有類的根類 Object,提供了一個 clone() 方法,該方法可以將一個 Java 對象復制一份,但是需要實現  clone() 的類必須要實現一個接口 Cloneable,該接口表示該類能夠復制且具有復制的能力。這就引出了原型模式。

基本介紹

  1. 原型模式(Prototype模式)是指:用原型實例指定創建對象的種類,并且通過拷貝這些原型,創建新的對象

  2. 原型模式是一種創建型設計模式, 使你能夠復制已有對象, 而又無需使代碼依賴它們所屬的類

  3. 工作原理是:通過將一個原型對象傳給那個要發動創建的對象,這個要發動創建的對象通過請求原型對象拷貝它們自己來實施創建,即  對象**.clone**()

類圖

什么是Java淺拷貝和深拷貝

  • Prototype : 原型 (Prototype) 接口將對克隆方法進行聲明

Java 中 Prototype 類需要具備以下兩個條件

  1. 實現 Cloneable 接口。在 Java 語言有一個 Cloneable  接口,它的作用只有一個,就是在運行時通知虛擬機可以安全地在實現了此接口的類上使用 clone 方法。在 Java  虛擬機中,只有實現了這個接口的類才可以被拷貝,否則在運行時會拋出 CloneNotSupportedException 異常

  2. 重寫 Object 類中的 clone 方法。Java 中,所有類的父類都是 Object 類,Object 類中有一個 clone  方法,作用是返回對象的一個拷貝

  • ConcretePrototype:具體原型 (Concrete Prototype) 類將實現克隆方法。除了將原始對象的數據復制到克隆體中之外,  該方法有時還需處理克隆過程中的極端情況, 例如克隆關聯對象和梳理遞歸依賴等等。

  • Client: 使用原型的客戶端,首先要獲取到原型實例對象,然后通過原型實例克隆自己,從而創建一個新的對象。

實例

“我們用王二小放羊的例子寫這個實例

1、原型類(實現 Clonable)

@Setter @Getter @NoArgsConstructor @AllArgsConstructor class Sheep implements Cloneable {     private String name;     private Integer age;     private String color;      @Override     protected Sheep clone() {         Sheep sheep = null;         try {             sheep = (Sheep) super.clone();         } catch (Exception e) {             System.out.println(e.getMessage());         }         return sheep;     } }

2、具體原型

按業務的不同實現不同的原型對象,假設現在主角是王二小,羊群里有山羊、綿羊一大群

public class Goat extends Sheep{     public void graze() {         System.out.println("山羊去吃草");     } }
public class Lamb extends Sheep{     public void graze() {         System.out.println("羔羊去吃草");     } }

3、客戶端

public class Client {      static List<Sheep> sheepList = new ArrayList<>();     public static void main(String[] args) {         Goat goat = new Goat();         goat.setName("山羊");         goat.setAge(3);         goat.setColor("灰色");         for (int i = 0; i < 5; i++) {             sheepList.add(goat.clone());         }          Lamb lamb = new Lamb();         lamb.setName("羔羊");         lamb.setAge(2);         lamb.setColor("白色");         for (int i = 0; i < 5; i++) {             sheepList.add(lamb.clone());             System.out.println(lamb.hashCode()+","+lamb.clone().hashCode());         }          for (Sheep sheep : sheepList) {             System.out.println(sheep.toString());         } }

原型模式將克隆過程委派給被克隆的實際對象。模式為所有支持克隆的對象聲明了一個通用接口,  該接口讓你能夠克隆對象,同時又無需將代碼和對象所屬類耦合。通常情況下,這樣的接口中僅包含一個 克隆方法。

所有的類對 克隆方法的實現都非常相似。該方法會創建一個當前類的對象, 然后將原始對象所有的成員變量值復制到新建的類中。你甚至可以復制私有成員變量,  因為絕大部分編程語言都允許對象訪問其同類對象的私有成員變量。

支持克隆的對象即為原型。當你的對象有幾十個成員變量和幾百種類型時, 對其進行克隆甚至可以代替子類的構造。

優勢

使用原型模式創建對象比直接 new 一個對象在性能上要好的多,因為 Object 類的 clone  方法是一個本地方法,它直接操作內存中的二進制流,特別是復制大對象時,性能的差別非常明顯。

使用原型模式的另一個好處是簡化對象的創建,使得創建對象就像我們在編輯文檔時的復制粘貼一樣簡單。

因為以上優點,所以在需要重復地創建相似對象時可以考慮使用原型模式。比如需要在一個循環體內創建對象,假如對象創建過程比較復雜或者循環次數很多的話,使用原型模式不但可以簡化創建過程,而且可以使系統的整體性能提高很多。

適用場景

《Head First 設計模式》是這么形容原型模式的:當創建給定類的實例的過程很昂貴或很復雜時,就是用原型模式。

如果你需要復制一些對象,同時又希望代碼獨立于這些對象所屬的具體類,可以使用原型模式。

如果子類的區別僅在于其對象的初始化方式, 那么你可以使用該模式來減少子類的數量。別人創建這些子類的目的可能是為了創建特定類型的對象

原型模式在 Spring 中的應用

我們都知道 Spring bean 默認是單例的,但是有些場景可能需要原型范圍,如下

<bean id="sheep" class="priv.starfish.prototype.Sheep" scope="prototype">    <property name="name" value="肖恩"/>    <property name="age" value="2"/>    <property name="color" value="白色"/> </bean>

同樣,王二小還是有 10 只羊,感興趣的也可以看下他們創建的對象是不是同一個

public class Client {     public static void main(String[] args) {         ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");         for (int i = 0; i < 10; i++) {             Object bean = context.getBean("sheep");             System.out.println(bean);         }     } }

感興趣的同學可以深入源碼看下具體的實現,在 AbstractBeanFactory 的 doGetBean() 方法中

什么是Java淺拷貝和深拷貝

原型模式的注意事項

  • 使用原型模式復制對象不會調用類的構造方法。因為對象的復制是通過調用 Object 類的 clone  方法來完成的,它直接在內存中復制數據,因此不會調用到類的構造方法。不但構造方法中的代碼不會執行,甚至連訪問權限都對原型模式無效。還記得單例模式嗎?單例模式中,只要將構造方法的訪問權限設置為  private 型,就可以實現單例。但是 clone 方法直接無視構造方法的權限,所以,單例模式與原型模式是沖突的,在使用時要特別注意。

  • 深拷貝與淺拷貝。Object 類的  clone方法只會拷貝對象中的基本的數據類型,對于數組、容器對象、引用對象等都不會拷貝,這就是淺拷貝。如果要實現深拷貝,必須將原型模式中的數組、容器對象、引用對象等另行拷貝。

淺拷貝和深拷貝

首先需要明白,淺拷貝和深拷貝都是針對一個已有對象的操作。

在 Java 中,除了基本數據類型(元類型)之外,還存在 類的實例對象 這個引用數據類型。而一般使用 『 =  』號做賦值操作的時候。對于基本數據類型,實際上是拷貝的它的值,但是對于對象而言,其實賦值的只是這個對象的引用,將原對象的引用傳遞過去,他們實際上還是指向的同一個對象。

而淺拷貝和深拷貝就是在這個基礎之上做的區分,如果在拷貝這個對象的時候,只對基本數據類型進行了拷貝,而對引用數據類型只是進行了引用的傳遞,而沒有真實的創建一個新的對象,則認為是淺拷貝。反之,在對引用數據類型進行拷貝的時候,創建了一個新的對象,并且復制其內的成員變量,則認為是深拷貝。

“所謂的淺拷貝和深拷貝,只是在拷貝對象的時候,對 類的實例對象 這種引用數據類型的不同操作而已

淺拷貝

  1. 對于數據類型是基本數據類型的成員變量,淺拷貝會直接進行值傳遞,也就是將該屬性值復制一份給新的對象。

  2. 對于數據類型是引用數據類型的成員變量,比如說成員變量是某個數組、某個類的對象等,那么淺拷貝會進行引用傳遞,也就是只是將該成員變量的引用值(內存地址)復制一份給新的對象。因為實際上兩個對象的該成員變量都指向同一個實例。在這種情況下,在一個對象中修改該成員變量會影響到另一個對象的該成員變量值

  3. 前面我們克隆羊就是淺拷貝,如果我們在 Sheep 中加一個對象類型的屬性,public Sheep child;可以看到 s 和 s1 的 friend  是同一個。

 Sheep s = new Sheep();   s.setName("sss");      s.friend = new Sheep();   s.friend.setName("喜洋洋");      Sheep s1 = s.clone();   System.out.println(s == s1);   System.out.println(s.hashCode()+"---"+s.clone().hashCode());      System.out.println(s.friend == s1.friend);   System.out.println(s.friend.hashCode() + "---" +s1.friend.hashCode()); false 621009875---1265094477 true 2125039532---2125039532

深拷貝

現在我們知道 clone() 方法,只能對當前對象進行淺拷貝,引用類型依然是在傳遞引用。那如何進行一個深拷貝呢?

常見的深拷貝實現方式有兩種:

  1. 重寫 clone 方法來實現深拷貝

  2. 通過對象序列化實現深拷貝

淺拷貝和深拷貝只是相對的,如果一個對象內部只有基本數據類型,那用 clone() 方法獲取到的就是這個對象的深拷貝,而如果其內部還有引用數據類型,那用  clone() 方法就是一次淺拷貝的操作。

感謝各位的閱讀,以上就是“什么是Java淺拷貝和深拷貝”的內容了,經過本文的學習后,相信大家對什么是Java淺拷貝和深拷貝這一問題有了更深刻的體會,具體使用情況還需要大家實踐驗證。這里是億速云,小編將為大家推送更多相關知識點的文章,歡迎關注!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

大新县| 平果县| 安庆市| 北辰区| 天长市| 泊头市| 股票| 克拉玛依市| 迁西县| 吐鲁番市| 大港区| 广南县| 安宁市| 洪江市| 太和县| 奎屯市| 射阳县| 临武县| 巴马| 鹤壁市| 苍梧县| 仁布县| 宁远县| 康马县| 资讯| 中方县| 泗水县| 驻马店市| 安陆市| 安乡县| 西平县| 鄄城县| 交城县| 鹿泉市| 新兴县| 永新县| 长海县| 峨眉山市| 昭通市| 临沭县| 淳化县|