日韩成人免费在线_国产成人一二_精品国产免费人成电影在线观..._日本一区二区三区久久久久久久久不

當(dāng)前位置:首頁(yè) > 科技  > 軟件

深入理解Java淺拷貝與深拷貝

來(lái)源: 責(zé)編: 時(shí)間:2024-03-18 09:39:35 200觀看
導(dǎo)讀淺拷貝和深拷貝是 Java 初中級(jí)面試中經(jīng)常會(huì)被問(wèn)到的一個(gè)問(wèn)題,兩個(gè)就像是兄弟倆,一個(gè)調(diào)皮一個(gè)乖巧,現(xiàn)在讓我們一起來(lái)探索它們的奇妙之處!特別說(shuō)明:不論是淺拷貝還是深拷貝,都可以使用Object類(lèi)的clone方法來(lái)實(shí)現(xiàn),代碼如下:prote

淺拷貝和深拷貝是 Java 初中級(jí)面試中經(jīng)常會(huì)被問(wèn)到的一個(gè)問(wèn)題,兩個(gè)就像是兄弟倆,一個(gè)調(diào)皮一個(gè)乖巧,現(xiàn)在讓我們一起來(lái)探索它們的奇妙之處!Fzq28資訊網(wǎng)——每日最新資訊28at.com

特別說(shuō)明:不論是淺拷貝還是深拷貝,都可以使用Object類(lèi)的clone方法來(lái)實(shí)現(xiàn),代碼如下:Fzq28資訊網(wǎng)——每日最新資訊28at.com

protected native Object clone() throws CloneNotSupportedException;

注意:clone()方法也是一個(gè)本地方法,具體實(shí)現(xiàn)交給虛擬機(jī),也就是說(shuō)虛擬機(jī)在運(yùn)行給方法時(shí),就會(huì)變成搞笑的C/C++代碼。Fzq28資訊網(wǎng)——每日最新資訊28at.com

1. 淺拷貝

先讓我們來(lái)了解一下淺拷貝。它就像是我們上學(xué)時(shí)抄了學(xué)霸一份作業(yè),但結(jié)果可能讓人出乎意料。為了演示這一點(diǎn),我們創(chuàng)建了一個(gè)名為Student的類(lèi),這個(gè)學(xué)生有一個(gè)名為“name”的字符串字段和一個(gè)名為“age”的整數(shù)字段。Fzq28資訊網(wǎng)——每日最新資訊28at.com

public class Student implements  Cloneable{    private int age;    private String name;    public Student(int age, String name) {        this.age = age;        this.name = name;    }    public int getAge() {        return age;    }    public void setAge(int age) {        this.age = age;    }    public String getName() {        return name;    }    public void setName(String name) {        this.name = name;    }    @Override    public String toString() {        return super.toString().substring(19) + "{" +                "age=" + age +                ", name='" + name + '/'' +                '}';    }    @Override    public   Object clone() throws CloneNotSupportedException {        return super.clone();    }}

接著,我們來(lái)進(jìn)行測(cè)試。假設(shè)我們有一個(gè)名叫“springboot葵花寶典”的Student對(duì)象,并進(jìn)行了淺拷貝。結(jié)果出來(lái)了!讓我們看看會(huì)發(fā)生什么。Fzq28資訊網(wǎng)——每日最新資訊28at.com

public class CloneTest {    public static void main(String[] args) throws CloneNotSupportedException {        Student student1 = new Student(18,"springboot葵花寶典");        Student student2 = (Student) student1.clone();        System.out.println("淺拷貝后:");        System.out.println("Student1:" + student1);        System.out.println("Student2:" + student2);        student2.setName("zbbmeta");        System.out.println("調(diào)整了Student2 的 name  后:");        System.out.println("Student1:" + student1);        System.out.println("Student2:" + student2);    }}

測(cè)試結(jié)果如下:Fzq28資訊網(wǎng)——每日最新資訊28at.com

淺拷貝后:Student1:Student@4cb2c100{age=18, name='springboot葵花寶典'}Student2:Student@39fb3ab6{age=18, name='springboot葵花寶典'}調(diào)整了Student2 的 name  后:Student1:Student@4cb2c100{age=18, name='springboot葵花寶典'}Student2:Student@39fb3ab6{age=18, name='zbbmeta'}

淺拷貝后,Student1 和 Student1 引用不同對(duì)象,但值是相同的,說(shuō)明拷貝成功。之后,修改了 Student2 的 name 字段,student2的name和student1的name值不同。Fzq28資訊網(wǎng)——每日最新資訊28at.com

Fzq28資訊網(wǎng)——每日最新資訊28at.com

圖片圖片Fzq28資訊網(wǎng)——每日最新資訊28at.com

注意:一個(gè)類(lèi)沒(méi)有實(shí)現(xiàn) Cloneable 接口,即便它重寫(xiě)了 clone() 方法,依然是無(wú)法調(diào)用該方法進(jìn)行對(duì)象克隆的,會(huì)拋出異常CloneNotSupportedException。Fzq28資訊網(wǎng)——每日最新資訊28at.com

Exception in thread "main" java.lang.CloneNotSupportedException: com.zbbmeta.entity.Student

Fzq28資訊網(wǎng)——每日最新資訊28at.com

思考:前面Student只有兩個(gè)基本類(lèi)型,沒(méi)有引用類(lèi)型,如果給Student添加一個(gè)自定義Book引用類(lèi)型,淺拷貝會(huì)是什么結(jié)果?Fzq28資訊網(wǎng)——每日最新資訊28at.com

public class Book {    private String bookName;    private int price;    public Book(String bookName, int price) {        this.bookName = bookName;        this.price = price;    }    //...   省略getter/setter 方法      @Override    public String toString() {        return super.toString().substring(19) +                " bookName='" + bookName + '/'' +                ", price=" + price +                '}';    }}

重新編寫(xiě)Studnet類(lèi):Fzq28資訊網(wǎng)——每日最新資訊28at.com

public class Student implements  Cloneable{    private int age;    private String name;    private Book book;    public Student(int age, String name, Book book) {        this.age = age;        this.name = name;        this.book = book;    }   //...   省略getter/setter 方法    @Override    public String toString() {        return super.toString().substring(19) +                " age=" + age +                ", name='" + name + '/'' +                ", book=" + book +                '}';    }    @Override    public   Object clone() throws CloneNotSupportedException {        return super.clone();    }}

比之前的例子多了一個(gè)自定義類(lèi)型的字段 book,clone() 方法并沒(méi)有任何改變。Fzq28資訊網(wǎng)——每日最新資訊28at.com

測(cè)試類(lèi)修改內(nèi)容如下:Fzq28資訊網(wǎng)——每日最新資訊28at.com

public static void main(String[] args) throws CloneNotSupportedException {        Student student1 = new Student(18,"springboot葵花寶典");        Book book1 = new Book("springboot入門(mén)到精通",90);        student1.setBook(book1);        Student student2 = (Student) student1.clone();        System.out.println("淺拷貝后:");        System.out.println("Student1:" + student1);        System.out.println("Student2:" + student2);        Book book2 = student2.getBook();        book2.setBookName("K8S實(shí)戰(zhàn)");        book2.setPrice(70);        System.out.println("調(diào)整了Student2 的 book  后:");        System.out.println("Student1:" + student1);        System.out.println("Student2:" + student2);    }

輸出結(jié)果如下:Fzq28資訊網(wǎng)——每日最新資訊28at.com

淺拷貝后:Student1:Student@6fb554cc age=18, name='springboot葵花寶典', book=Book@3c09711b bookName='springboot入門(mén)到精通', price=90}}Student2:Student@3a82f6ef age=18, name='springboot葵花寶典', book=Book@3c09711b bookName='springboot入門(mén)到精通', price=90}}調(diào)整了Student2 的 book  后:Student1:Student@6fb554cc age=18, name='springboot葵花寶典', book=Book@3c09711b bookName='K8S實(shí)戰(zhàn)', price=70}}Student2:Student@3a82f6ef age=18, name='springboot葵花寶典', book=Book@3c09711b bookName='K8S實(shí)戰(zhàn)', price=70}}

student2.book 變更后,student1.book 也發(fā)生了改變。這是因?yàn)閚ame字符串 String 是不可變對(duì)象,一個(gè)新的值必須在字符串常量池中開(kāi)辟一段新的內(nèi)存空間,而B(niǎo)ook是自定義對(duì)象的內(nèi)存地址并沒(méi)有發(fā)生改變,只是對(duì)應(yīng)的字段值發(fā)生了改變。Fzq28資訊網(wǎng)——每日最新資訊28at.com

Fzq28資訊網(wǎng)——每日最新資訊28at.com

Fzq28資訊網(wǎng)——每日最新資訊28at.com

總結(jié):淺拷貝是創(chuàng)建一個(gè)新的對(duì)象,這個(gè)對(duì)象有著對(duì)原始對(duì)象屬性值的一份精確拷貝。如果屬性是基本數(shù)據(jù)類(lèi)型,拷貝的就是基本數(shù)據(jù)類(lèi)型的值;如果屬性是引用數(shù)據(jù)類(lèi)型,拷貝的就是內(nèi)存地址,所以如果其中一個(gè)對(duì)象改變了引用類(lèi)型的數(shù)據(jù),就會(huì)影響另一個(gè)對(duì)象。Fzq28資訊網(wǎng)——每日最新資訊28at.com

2. 深拷貝

深拷貝和淺拷貝不同的,深拷貝中的引用類(lèi)型字段也會(huì)克隆一份,當(dāng)改變?nèi)魏我粋€(gè)對(duì)象,另外一個(gè)對(duì)象不會(huì)隨之改變。例子如下:Fzq28資訊網(wǎng)——每日最新資訊28at.com

public class Book implements Cloneable{    private String bookName;    private int price;    public Book(String bookName, int price) {        this.bookName = bookName;        this.price = price;    } //...   省略getter/setter 方法    @Override    public String toString() {        return super.toString().substring(19) +                " bookName='" + bookName + '/'' +                ", price=" + price +                '}';    }    @Override    public Object clone() throws CloneNotSupportedException {        return super.clone();    }}

注意:此時(shí)的 Book 類(lèi)和淺拷貝時(shí)不同,重寫(xiě)了 clone() 方法,并實(shí)現(xiàn)了 Cloneable 接口。為的就是深拷貝的時(shí)候也能夠克隆該字段。Fzq28資訊網(wǎng)——每日最新資訊28at.com

重新編寫(xiě)Studnet類(lèi):Fzq28資訊網(wǎng)——每日最新資訊28at.com

public class Student implements  Cloneable{    private int age;    private String name;    private Book book;    public Student(int age, String name, Book book) {        this.age = age;        this.name = name;        this.book = book;    }   //...   省略getter/setter 方法    @Override    public String toString() {        return super.toString().substring(19) +                " age=" + age +                ", name='" + name + '/'' +                ", book=" + book +                '}';    }    @Override    public Object clone() throws CloneNotSupportedException {        Student student = (Student) super.clone();        student.setBook((Book) student.getBook().clone());        return student;    }}

注意,此時(shí) Student 類(lèi)也與之前的不同,clone() 方法當(dāng)中,不再只調(diào)用 Object 的 clone() 方法對(duì) Student 進(jìn)行克隆了,還對(duì) Book 也進(jìn)行了克隆。Fzq28資訊網(wǎng)——每日最新資訊28at.com

測(cè)試結(jié)果如下:Fzq28資訊網(wǎng)——每日最新資訊28at.com

淺拷貝后:Student1:Student@6fb554cc age=18, name='springboot葵花寶典', book=Book@3c09711b bookName='springboot入門(mén)到精通', price=90}}Student2:Student@3a82f6ef age=18, name='springboot葵花寶典', book=Book@100fc185 bookName='springboot入門(mén)到精通', price=90}}調(diào)整了Student2 的 book  后:Student1:Student@6fb554cc age=18, name='springboot葵花寶典', book=Book@3c09711b bookName='springboot入門(mén)到精通', price=90}}Student2:Student@3a82f6ef age=18, name='springboot葵花寶典', book=Book@100fc185 bookName='K8S實(shí)戰(zhàn)', price=70}}

發(fā)現(xiàn): 不僅student1 和 student2 對(duì)象不同,它們中的 book 對(duì)象不同。所以,改變了 student2 中的 book 并不會(huì)影響到 student1。Fzq28資訊網(wǎng)——每日最新資訊28at.com

Fzq28資訊網(wǎng)——每日最新資訊28at.com

圖片圖片Fzq28資訊網(wǎng)——每日最新資訊28at.com

思考:嵌套的對(duì)象比較多的時(shí),每一個(gè)類(lèi)都需要重寫(xiě)clone()方法,這樣拷貝起來(lái)就比較麻煩,那么有沒(méi)有別的方法實(shí)現(xiàn)深拷貝。Fzq28資訊網(wǎng)——每日最新資訊28at.com

利用序列化,序列化是將對(duì)象寫(xiě)到流中便于傳輸,而反序列化則是將對(duì)象從流中讀取出來(lái)。寫(xiě)入流中的對(duì)象就是對(duì)原始對(duì)象的拷貝。需要注意的是,每個(gè)要序列化的類(lèi)都要實(shí)現(xiàn) Serializable 接口,該接口和 Cloneable 接口類(lèi)似,都是標(biāo)記型接口。Fzq28資訊網(wǎng)——每日最新資訊28at.com

public class Book implements Cloneable{    private String bookName;    private int price;    public Book(String bookName, int price) {        this.bookName = bookName;        this.price = price;    } //...   省略getter/setter 方法    @Override    public String toString() {        return super.toString().substring(19) +                " bookName='" + bookName + '/'' +                ", price=" + price +                '}';    }}

注意:Book 需要實(shí)現(xiàn) Serializable 接口。Fzq28資訊網(wǎng)——每日最新資訊28at.com

重新編寫(xiě)Studnet類(lèi):Fzq28資訊網(wǎng)——每日最新資訊28at.com

public class Student implements  Cloneable{    private int age;    private String name;    private Book book;    public Student(int age, String name, Book book) {        this.age = age;        this.name = name;        this.book = book;    }   //...   省略getter/setter 方法    @Override    public String toString() {        return super.toString().substring(19) +                " age=" + age +                ", name='" + name + '/'' +                ", book=" + book +                '}';    }    //深度拷貝    public Object deepClone() throws IOException, ClassNotFoundException {        // 序列化        ByteArrayOutputStream bos = new ByteArrayOutputStream();        ObjectOutputStream oos = new ObjectOutputStream(bos);        oos.writeObject(this);        // 反序列化        ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());        ObjectInputStream ois = new ObjectInputStream(bis);        return ois.readObject();    }}

注意:Student 類(lèi)實(shí)現(xiàn) Serializable 接口,并且在該類(lèi)中,增加了一個(gè) deepClone() 的方法,利用 OutputStream 進(jìn)行序列化,InputStream 進(jìn)行反序列化,這樣就實(shí)現(xiàn)了深拷貝。Fzq28資訊網(wǎng)——每日最新資訊28at.com

public static void main(String[] args) throws  IOException, ClassNotFoundException {        Student student1 = new Student(18,"springboot葵花寶典");        Book book1 = new Book("springboot入門(mén)到精通",90);        student1.setBook(book1);        Student student2 = (Student) student1.deepClone();        System.out.println("淺拷貝后:");        System.out.println("Student1:" + student1);        System.out.println("Student2:" + student2);        Book book2 = student2.getBook();        book2.setBookName("K8S實(shí)戰(zhàn)");        book2.setPrice(70);        System.out.println("調(diào)整了Student2 的 book  后:");        System.out.println("Student1:" + student1);        System.out.println("Student2:" + student2);    }

與之前測(cè)試類(lèi)不同的是,調(diào)用了 deepClone() 方法。Fzq28資訊網(wǎng)——每日最新資訊28at.com

測(cè)試結(jié)果如下:Fzq28資訊網(wǎng)——每日最新資訊28at.com

淺拷貝后:Student1:Student@5dfcfece age=18, name='springboot葵花寶典', book=Book@5d5eef3d bookName='springboot入門(mén)到精通', price=90}}Student2:Student@5a8e6209 age=18, name='springboot葵花寶典', book=Book@4b4523f8 bookName='springboot入門(mén)到精通', price=90}}調(diào)整了Student2 的 book  后:Student1:Student@5dfcfece age=18, name='springboot葵花寶典', book=Book@5d5eef3d bookName='springboot入門(mén)到精通', price=90}}Student2:Student@5a8e6209 age=18, name='springboot葵花寶典', book=Book@4b4523f8 bookName='K8S實(shí)戰(zhàn)', price=70}}

測(cè)試結(jié)果和之前用 clone() 方法實(shí)現(xiàn)的深拷貝類(lèi)似。Fzq28資訊網(wǎng)——每日最新資訊28at.com

特別說(shuō)明:序列化涉及到輸入流和輸出流的讀寫(xiě),在性能上要比  虛擬機(jī)實(shí)現(xiàn)的 clone() 方法差很多。Fzq28資訊網(wǎng)——每日最新資訊28at.com

本文鏈接:http://www.www897cc.com/showinfo-26-76500-0.html深入理解Java淺拷貝與深拷貝

聲明:本網(wǎng)頁(yè)內(nèi)容旨在傳播知識(shí),若有侵權(quán)等問(wèn)題請(qǐng)及時(shí)與本網(wǎng)聯(lián)系,我們將在第一時(shí)間刪除處理。郵件:2376512515@qq.com

上一篇: Synchronized關(guān)鍵字的底層原理?

下一篇: VR在工業(yè)培訓(xùn)中的興起,讓明天更安全

標(biāo)簽:
  • 熱門(mén)焦點(diǎn)
Top 主站蜘蛛池模板: 青州市| 临城县| 辽源市| 邵阳县| 徐水县| 华坪县| 扶绥县| 榕江县| 黄梅县| 玉树县| 沅陵县| 九龙城区| 渑池县| 奈曼旗| 贵州省| 建平县| 延安市| 榆林市| 金昌市| 女性| 长海县| 湖北省| 渭源县| 太仆寺旗| 阳曲县| 平湖市| 西乌珠穆沁旗| 肃宁县| 永泰县| 东光县| 固安县| 兴海县| 株洲县| 通许县| 托克托县| 盐边县| 焦作市| 浑源县| 亚东县| 南丰县| 易门县|