亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

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

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

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

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

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

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

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

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

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

什么是深拷貝和淺拷貝

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

  • 淺拷貝(Shallow Copy):

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

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

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

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

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

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

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

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

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

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

淺拷貝示例

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

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

下面是一個(gè)示例代碼,演示了如何使用 Cloneable 接口和 clone() 方法實(shí)現(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)建了一個(gè) Person 類,并實(shí)現(xiàn)了 Cloneable 接口。在 clone() 方法中直接調(diào)用了父類的 clone() 方法,并進(jìn)行了類型轉(zhuǎn)換。通過調(diào)用 clone() 方法,可以得到一個(gè)新的對(duì)象 person2,它與原始對(duì)象 person1 具有相同的屬性值。當(dāng)修改 person2 的屬性時(shí),不會(huì)影響到 person1。

深拷貝示例

使用序列化和反序列化:

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

下面是一個(gè)示例代碼,演示了如何使用序列化和反序列化實(shí)現(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)建了一個(gè) Address 類和一個(gè) Person 類,它們都實(shí)現(xiàn)了 Serializable 接口。通過序列化和反序列化操作,我們可以實(shí)現(xiàn)深拷貝。在 deepCopy() 方法中,我們使用字節(jié)流將對(duì)象寫入到內(nèi)存中,并從內(nèi)存中讀取出來,從而得到一個(gè)新的獨(dú)立對(duì)象。通過調(diào)用 deepCopy() 方法,可以得到一個(gè)新的對(duì)象 person2,它與原始對(duì)象 person1 完全獨(dú)立。在修改 person2 的屬性時(shí),不會(huì)影響到 person1。 值得注意的是,要實(shí)現(xiàn)深拷貝,所有相關(guān)的類都需要實(shí)現(xiàn) Serializable 接口。

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

深拷貝(Deep Copy):

  • 適用場(chǎng)景:

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

    • 深拷貝將源對(duì)象及其關(guān)聯(lián)的全部對(duì)象進(jìn)行遞歸復(fù)制,每個(gè)對(duì)象都擁有獨(dú)立的內(nèi)存空間,修改副本對(duì)象不會(huì)影響原始對(duì)象。
  • 實(shí)現(xiàn)方式:

    • 使用遞歸或者拷貝構(gòu)造函數(shù)來復(fù)制對(duì)象及其子對(duì)象的屬性。
  • 示例場(chǎng)景:

    • 復(fù)制復(fù)雜對(duì)象的副本,使其成為獨(dú)立的個(gè)體,例如:拷貝一個(gè)包含集合、嵌套對(duì)象等的數(shù)據(jù)結(jié)構(gòu)。
    • 對(duì)象圖的克隆,當(dāng)原對(duì)象包含子對(duì)象,并且對(duì)子對(duì)象的修改不應(yīng)該影響原對(duì)象時(shí)。

淺拷貝(Shallow Copy):

  • 適用場(chǎng)景:

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

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

    • 通常使用對(duì)象的 clone() 方法來進(jìn)行淺拷貝。
  • 示例場(chǎng)景:

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

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

相關(guān)文章

最新評(píng)論