欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

一文搞懂Java克隆及深拷貝與淺拷貝的區(qū)別

 更新時間:2023年08月02日 11:52:44   作者:蜀山劍客李沐白  
在編程中,通常通過實現(xiàn)Cloneable接口和重寫clone方法來實現(xiàn)對象的克隆,然而,需要注意的是克隆操作可能存在深拷貝和淺拷貝的區(qū)別,在使用時需要根據(jù)實際需求選擇合適的克隆方式,本文就給大家詳細講講什么是克隆以及深拷貝與淺拷貝的區(qū)別,需要的朋友可以參考下

什么是克隆,為什么在編程中使用克隆

克隆是指創(chuàng)建一個對象的副本,使得新創(chuàng)建的對象在內容上與原始對象相同。在編程中,克隆是常用的技術之一,它具有以下幾個重要用途和優(yōu)勢:

  • 復制對象:使用克隆可以創(chuàng)建一個與原始對象相同的新對象,包括對象的屬性和狀態(tài)。這樣可以在不影響原始對象的情況下,對新對象進行修改、操作、傳遞等。這在某些場景下非常有用,可以避免重新創(chuàng)建和初始化一個對象。

  • 隔離性與保護:通過克隆,可以創(chuàng)建一個獨立于原始對象的副本。這樣,修改克隆對象時,不會影響到原始對象,從而實現(xiàn)了對象之間的隔離性。這對于多線程環(huán)境下的并發(fā)操作或者保護重要數(shù)據(jù)具有重要意義。

  • 性能優(yōu)化:有時候,通過克隆對象可以提高程序的性能。在某些場景下,對象的創(chuàng)建和初始化過程可能較為耗時,如果需要多次使用這個對象,通過克隆原始對象可以避免重復的創(chuàng)建和初始化過程,從而提高程序的執(zhí)行效率。

  • 原型模式:克隆在設計模式中有一個重要的角色,即原型模式。原型模式通過克隆來創(chuàng)建對象的實例,而不是使用傳統(tǒng)的構造函數(shù)。這樣可以提供更靈活的對象創(chuàng)建方式,并且避免了頻繁的子類化。

在編程中,通常通過實現(xiàn)Cloneable接口和重寫clone方法來實現(xiàn)對象的克隆。然而,需要注意的是克隆操作可能存在深拷貝和淺拷貝的區(qū)別,在使用時需要根據(jù)實際需求選擇合適的克隆方式。

什么是深拷貝和淺拷貝

深拷貝(Deep Copy)和淺拷貝(Shallow Copy)是在克?。–lone)操作中經常遇到的兩個概念,它們描述了克隆操作對于對象內部引用的處理方式。

  • 淺拷貝(Shallow Copy):

    • 淺拷貝指在克隆操作中,只復制對象本身以及對象內部的基本數(shù)據(jù)類型的屬性,而不復制對象內部的引用類型的屬性。
    • 淺拷貝僅僅創(chuàng)建了一個新對象,該對象與原始對象共享對同一引用類型屬性的訪問。如果原始對象的引用類型屬性被修改,淺拷貝的對象也會受到影響。
    • 在淺拷貝中,新對象和原始對象指向同一塊內存區(qū)域,因此對其中一個對象進行修改可能會影響到另一個對象。
  • 深拷貝(Deep Copy):

    • 深拷貝指在克隆操作中,除了復制對象本身以及對象內部的基本數(shù)據(jù)類型的屬性外,還要遞歸地復制對象內部的引用類型的屬性。即深度克隆了所有引用類型的屬性。
    • 深拷貝創(chuàng)建了一個完全獨立的新對象,該對象與原始對象沒有任何關聯(lián),對新對象和原始對象的修改互不影響。
    • 在深拷貝中,新對象和原始對象分別對應不同的內存區(qū)域,它們之間不存在引用關系,因此修改其中一個對象不會影響到另一個對象。

為了實現(xiàn)深拷貝,需要對對象內部的引用類型屬性進行遞歸復制。常見的實現(xiàn)深拷貝的方式包括:

  • 通過序列化和反序列化:將對象序列化為字節(jié)流,然后再反序列化為新的對象,這樣可以創(chuàng)建一個與原始對象完全獨立的副本。
  • 通過逐個復制引用類型屬性:對于每個引用類型的屬性,創(chuàng)建一個新的實例并將原始對象屬性的內容復制到新的實例中。

需要注意的是,并非所有對象都能進行深拷貝。某些對象或者類中的屬性可能是不可變的,無需拷貝;某些對象可能包含循環(huán)引用,無法完全復制。因此,在進行克隆操作時,需要根據(jù)具體情況選擇合適的拷貝方式。

深拷貝和淺拷貝的主要區(qū)別在于對于對象內部引用類型屬性的處理方式。

  • 數(shù)據(jù)復制層次的深度:

    • 淺拷貝只復制對象本身以及對象內部的基本數(shù)據(jù)類型的屬性,不會遞歸地復制引用類型的屬性。因此,在淺拷貝中,新對象和原始對象共享對同一引用類型屬性的訪問。
    • 深拷貝除了復制對象本身和基本數(shù)據(jù)類型的屬性外,還會遞歸地復制對象內部的引用類型的屬性。這樣,深拷貝創(chuàng)建了一個完全獨立的新對象,與原始對象沒有任何關聯(lián)。
  • 對象之間的關聯(lián)性:

    • 淺拷貝得到的新對象與原始對象共享對同一引用類型屬性的訪問。如果對其中一個對象的引用類型屬性進行修改,另一個對象也會受到影響。
    • 深拷貝得到的新對象與原始對象沒有任何關聯(lián),修改其中一個對象的引用類型屬性不會影響到另一個對象。
  • 內存區(qū)域的分配:

    • 在淺拷貝中,新對象和原始對象指向同一塊內存區(qū)域。因此,對其中一個對象進行修改可能會影響到另一個對象。
    • 在深拷貝中,新對象和原始對象分別對應不同的內存區(qū)域,它們之間不存在引用關系,因此修改其中一個對象不會影響到另一個對象。

淺拷貝示例

實現(xiàn) Cloneable 接口和重寫 clone() 方法:

  • Java 中的 Cloneable 接口是一個標記接口,沒有定義任何方法。通過實現(xiàn) Cloneable 接口并重寫 clone() 方法,可以實現(xiàn)對象的淺拷貝。
  • 在 clone() 方法中,調用父類的 clone() 方法,并將其返回值進行類型轉換即可完成淺拷貝。

下面是一個示例代碼,演示了如何使用 Cloneable 接口和 clone() 方法實現(xiàn)淺拷貝:

class Person implements Cloneable {
    private String name;
    private int age;
    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }
    public void setName(String name) {
        this.name = name;
    }
    public void setAge(int age) {
        this.age = age;
    }
    public String getName() {
        return name;
    }
    public int getAge() {
        return age;
    }
    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}
public class Main {
    public static void main(String[] args) {
        Person person1 = new Person("Alice", 25);
        try {
            // 淺拷貝
            Person person2 = (Person) person1.clone();
            System.out.println(person1.getName() + " " + person1.getAge()); // Alice 25
            System.out.println(person2.getName() + " " + person2.getAge()); // Alice 25
            person2.setName("Bob");
            person2.setAge(30);
            System.out.println(person1.getName() + " " + person1.getAge()); // Alice 25
            System.out.println(person2.getName() + " " + person2.getAge()); // Bob 30
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
    }
}

在上述示例中,我們創(chuàng)建了一個 Person 類,并實現(xiàn)了 Cloneable 接口。在 clone() 方法中直接調用了父類的 clone() 方法,并進行了類型轉換。通過調用 clone() 方法,可以得到一個新的對象 person2,它與原始對象 person1 具有相同的屬性值。當修改 person2 的屬性時,不會影響到 person1。

深拷貝示例

使用序列化和反序列化:

  • 將對象寫入到字節(jié)流中,然后再從字節(jié)流中讀取出來,這個過程會重新創(chuàng)建一個完全獨立的對象,實現(xiàn)了深拷貝。
  • 為了實現(xiàn)深拷貝,需要將對象及其關聯(lián)的對象都實現(xiàn)序列化。

下面是一個示例代碼,演示了如何使用序列化和反序列化實現(xiàn)深拷貝:

import java.io.*;
class Address implements Serializable {
    private String city;
    private String street;
    public Address(String city, String street) {
        this.city = city;
        this.street = street;
    }
    public void setCity(String city) {
        this.city = city;
    }
    public void setStreet(String street) {
        this.street = street;
    }
    public String getCity() {
        return city;
    }
    public String getStreet() {
        return street;
    }
}
class Person implements Serializable {
    private String name;
    private int age;
    private Address address;
    public Person(String name, int age, Address address) {
        this.name = name;
        this.age = age;
        this.address = address;
    }
    public void setName(String name) {
        this.name = name;
    }
    public void setAge(int age) {
        this.age = age;
    }
    public void setAddress(Address address) {
        this.address = address;
    }
    public String getName() {
        return name;
    }
    public int getAge() {
        return age;
    }
    public Address getAddress() {
        return address;
    }
}
public class Main {
    public static void main(String[] args) {
        Address address = new Address("City", "Street");
        Person person1 = new Person("Alice", 25, address);
        // 深拷貝
        Person person2 = deepCopy(person1);
        System.out.println(person1.getName() + " " + person1.getAge() + " " + person1.getAddress().getCity()); // Alice 25 City
        System.out.println(person2.getName() + " " + person2.getAge() + " " + person2.getAddress().getCity()); // Alice 25 City
        person2.setName("Bob");
        person2.setAge(30);
        person2.getAddress().setCity("New City");
        System.out.println(person1.getName() + " " + person1.getAge() + " " + person1.getAddress().getCity()); // Alice 25 City
        System.out.println(person2.getName() + " " + person2.getAge() + " " + person2.getAddress().getCity()); // Bob 30 New City
    }
    public static <T extends Serializable> T deepCopy(T object) {
        try {
            ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
            ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteArrayOutputStream);
            objectOutputStream.writeObject(object);
            objectOutputStream.flush();
            ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(byteArrayOutputStream.toByteArray());
            ObjectInputStream objectInputStream = new ObjectInputStream(byteArrayInputStream);
            return (T) objectInputStream.readObject();
        } catch (IOException | ClassNotFoundException e) {
            e.printStackTrace();
            return null;
        }
    }
}

在上述示例中,我們創(chuàng)建了一個 Address 類和一個 Person 類,它們都實現(xiàn)了 Serializable 接口。通過序列化和反序列化操作,我們可以實現(xiàn)深拷貝。在 deepCopy() 方法中,我們使用字節(jié)流將對象寫入到內存中,并從內存中讀取出來,從而得到一個新的獨立對象。通過調用 deepCopy() 方法,可以得到一個新的對象 person2,它與原始對象 person1 完全獨立。在修改 person2 的屬性時,不會影響到 person1。 值得注意的是,要實現(xiàn)深拷貝,所有相關的類都需要實現(xiàn) Serializable 接口。

深拷貝和淺拷貝的區(qū)別

深拷貝(Deep Copy):

  • 適用場景:

    • 當源對象包含引用類型的屬性時,如果需要復制對象及其子對象的所有屬性,而不僅僅只是復制引用,就需要使用深拷貝。
    • 當希望修改副本對象的屬性不影響原始對象時,需要使用深拷貝。
  • 工作原理:

    • 深拷貝將源對象及其關聯(lián)的全部對象進行遞歸復制,每個對象都擁有獨立的內存空間,修改副本對象不會影響原始對象。
  • 實現(xiàn)方式:

    • 使用遞歸或者拷貝構造函數(shù)來復制對象及其子對象的屬性。
  • 示例場景:

    • 復制復雜對象的副本,使其成為獨立的個體,例如:拷貝一個包含集合、嵌套對象等的數(shù)據(jù)結構。
    • 對象圖的克隆,當原對象包含子對象,并且對子對象的修改不應該影響原對象時。

淺拷貝(Shallow Copy):

  • 適用場景:

    • 當源對象的屬性全為基本數(shù)據(jù)類型或者不可變對象,并且不需要復制引用類型的屬性時,可以使用淺拷貝。
    • 當希望修改副本對象的屬性同時影響原始對象時,可以使用淺拷貝。
  • 工作原理:

    • 淺拷貝只復制對象及其引用,而不復制引用指向的實際對象,新舊對象將共享同一個引用對象。修改副本對象會影響原始對象。
  • 實現(xiàn)方式:

    • 通常使用對象的 clone() 方法來進行淺拷貝。
  • 示例場景:

    • 快速創(chuàng)建對象副本,以便在某些操作中對其進行修改,同時保留原始對象。
    • 在某些情況下,共享一部分數(shù)據(jù)以節(jié)省內存和提高性能。

以上就是一文搞懂Java克隆技術及深拷貝與淺拷貝的區(qū)別的詳細內容,更多關于Java克隆技術及深拷貝與淺拷貝的資料請關注腳本之家其它相關文章!

相關文章

最新評論