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

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > java >内容正文

java

java deep clone util_Java Clone深拷贝与浅拷贝的两种实现方法

發布時間:2023/12/19 java 40 豆豆
生活随笔 收集整理的這篇文章主要介紹了 java deep clone util_Java Clone深拷贝与浅拷贝的两种实现方法 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

1.首先,你要知道怎么實現克隆:實現Cloneable接口,在bean里面重寫clone()方法,權限為public。

2.其次,你要大概知道什么是地址傳遞,什么是值傳遞。

3.最后,你要知道你為什么使用這個clone方法。

先看第一條,簡單的克隆代碼的實現。這個也就是我們在沒了解清楚這個Java的clone的時候,會出現的問題。

看完代碼,我再說明這個時候的問題。

先看我要克隆的學生bean的代碼:

package com.lxk.model;

/**

* 學生類:有2個屬性:1,基本屬性-String-name;2,引用類型-Car-car。

*

* Created by lxk on 2017/3/23

*/

public class Student implements Cloneable {

private String name;

private Car car;

public String getName() {

return name;

}

public void setName(String name) {

this.name = name;

}

public Car getCar() {

return car;

}

public void setCar(Car car) {

this.car = car;

}

@Override

public String toString() {

return "Student{" +

"name='" + name + '\'' +

", car=" + car +

'}';

}

@Override

public Student clone() {

Student student = null;

try {

student = (Student) super.clone();

} catch (CloneNotSupportedException ignored) {

System.out.println(ignored.getMessage());

}

return student;

}

}

學生內部引用了Car這個bean

package com.lxk.model;

import java.util.List;

public class Car implements Comparable {

private String sign;

private int price;

private List myDog;

private List boys;

public Car() {

}

public Car(String sign, int price) {

this.sign = sign;

this.price = price;

}

public Car(String sign, int price, List myDog) {

this.sign = sign;

this.price = price;

this.myDog = myDog;

}

public Car(String sign, int price, List myDog, List boys) {

this.sign = sign;

this.price = price;

this.myDog = myDog;

this.boys = boys;

}

public String getSign() {

return sign;

}

public void setSign(String sign) {

this.sign = sign;

}

public int getPrice() {

return price;

}

public void setPrice(int price) {

this.price = price;

}

public List getMyDog() {

return myDog;

}

public void setMyDog(List myDog) {

this.myDog = myDog;

}

public List getBoys() {

return boys;

}

public void setBoys(List boys) {

this.boys = boys;

}

@Override

public int compareTo(Car o) {

//同理也可以根據sign屬性排序,就不舉例啦。

return this.getPrice() - o.getPrice();

}

@Override

public String toString() {

return "Car{" +

"sign='" + sign + '\'' +

", price=" + price +

", myDog=" + myDog +

", boys=" + boys +

'}';

}

}

最后就是main測試類

package com.lxk.findBugs;

import com.lxk.model.Car;

import com.lxk.model.Student;

/**

* 引用傳遞也就是地址傳遞需要注意的地方,引起的bug

*

* Created by lxk on 2017/3/23

*/

public class Bug2 {

public static void main(String[] args) {

Student student1 = new Student();

Car car = new Car("oooo", 100);

student1.setCar(car);

student1.setName("lxk");

//克隆完之后,student1和student2應該沒關系的,修改student1不影響student2的值,但是完之后發現,你修改car的值,student2也受影響啦。

Student student2 = student1.clone();

System.out.println("學生2:" + student2);//先輸出student2剛剛克隆完之后的值,然后在修改student1的相關引用類型的屬性值(car)和基本屬性值(name)

car.setSign("X5");

student1.setName("xxx");

System.out.println("學生2:" + student2);//再次輸出看修改的結果

}

}

之后就該是執行的結果圖了:

對上面執行結果的疑惑,以及解釋說明:

我們可能覺得自己在bean里面實現clone接口,重寫了這個clone方法,那么學生2是經由學生1clone,復制出來的,

那么學生1和學生2,應該是毫不相干的,各自是各自,然后,在修改學生1的時候,學生2是不會受影響的。

但是結果,不盡人意。從上圖執行結果可以看出來,除了名字,這個屬性是沒有被學生1影響,關于car的sign屬性已經因為學生1的變化而變化,這不是我希望的結果。

可見,這個簡單的克隆實現也僅僅是個“淺克隆”,也就是基本類型數據,他是會給你重新復制一份新的,但是引用類型的,他就不會重新復制份新的。引用類型包括,上面的其他bean的引用,list集合,等一些引用類型。

那么怎么實現深克隆呢?

對上述代碼稍作修改,如下:

學生bean的clone重寫方法如下所示:

@Override

public Student clone() {

Student student = null;

try {

student = (Student) super.clone();

if (car != null) {

student.setCar(car.clone());

}

} catch (CloneNotSupportedException ignored) {

System.out.println(ignored.getMessage());

}

return student;

}

然后還要Car類實現cloneable接口,復寫clone方法:

@Override

public Car clone() {

Car car = null;

try {

car = (Car) super.clone();

if (myDog != null) {

car.setMyDog(Lists.newArrayList(myDog));

}

if (boys != null) {

car.setBoys(Lists.newArrayList(boys));

}

} catch (CloneNotSupportedException ignored) {

System.out.println(ignored.getMessage());

}

return car;

}

主測試代碼不動,這個時候的執行結果如下:

可以看到,這個時候,你再修改學生1的值,就不會影響到學生2的值,這才是真正的克隆,也就是所謂的深克隆。

怎么舉一反三?

可以看到,這個例子里面的引用類型就一個Car類型的屬性,但是實際開發中,除了這個引用其他bean類型的屬性外,可能還要list類型的屬性值用的最多。

那么要怎么深克隆呢,就像我在Car bean類里面做的那樣,把所有的引用類型的屬性,都在clone一遍。那么你在最上層調用這個clone方法的時候,他就是真的深克隆啦。

我代碼里面那么判斷是為了避免空指針異常。當然,這個你也得注意咯。

注意 重寫clone方法的時候,里面各個屬性的null的判斷哦。

上面的是override clone()方法來實現深克隆的。如果你這個要克隆的對象很復雜的話,你就不得不去每個引用到的對象去復寫這個clone方法,這個太啰嗦來,改的地方,太多啦。

還有個方法就是使用序列化來實現這個深拷貝

/**

* 對象的深度克隆,此處的對象涉及Collection接口和Map接口下對象的深度克隆

* 利用序列化和反序列化的方式進行深度克隆對象

*

* @param object 待克隆的對象

* @param 待克隆對象的數據類型

* @return 已經深度克隆過的對象

*/

public static T deepCloneObject(T object) {

T deepClone = null;

ByteArrayOutputStream baos = null;

ObjectOutputStream oos = null;

ByteArrayInputStream bais = null;

ObjectInputStream ois = null;

try {

baos = new ByteArrayOutputStream();

oos = new ObjectOutputStream(baos);

oos.writeObject(object);

bais = new ByteArrayInputStream(baos

.toByteArray());

ois = new ObjectInputStream(bais);

deepClone = (T)ois.readObject();

} catch (IOException | ClassNotFoundException e) {

e.printStackTrace();

} finally {

try {

if(baos != null) {

baos.close();

}

} catch (IOException e) {

e.printStackTrace();

}

try {

if(oos != null) {

oos.close();

}

} catch (IOException e) {

e.printStackTrace();

}

try{

if(bais != null) {

bais.close();

}

} catch (IOException e) {

e.printStackTrace();

}

try{

if(ois != null) {

ois.close();

}

} catch (IOException e) {

e.printStackTrace();

}

}

return deepClone;

}

具體的使用如下:

/**

* 使用序列化來實現深拷貝簡單。但是,所涉及到的所有對象都的實現序列化接口。

*/

private static void cloneBySerializable() {

Student student1 = new Student();

Car car = new Car("oooo", 100, Lists.newArrayList(new Dog("aaa", true, true)));

student1.setCar(car);

student1.setName("lxk");

Student student2 = deepCloneObject(student1);

System.out.println("學生2:" + student2);

car.setSign("X5");

car.setMyDog(null);

student1.setName("xxx");

System.out.println("學生2:" + student2);

}

實現的效果,還是和上面的一樣的,但是這個就簡單多來,只需要給涉及到的每個引用類型,都去實現序列化接口就好啦。

總結

以上就是這篇文章的全部內容了,希望本文的內容對大家的學習或者工作具有一定的參考學習價值,謝謝大家對聚米學院的支持。如果你想了解更多相關內容請查看下面相關鏈接

創作挑戰賽新人創作獎勵來咯,堅持創作打卡瓜分現金大獎

總結

以上是生活随笔為你收集整理的java deep clone util_Java Clone深拷贝与浅拷贝的两种实现方法的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。