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

溫馨提示×

溫馨提示×

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

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

怎么在Java中利用Clone實現深拷貝與淺拷貝

發布時間:2021-05-14 18:00:09 來源:億速云 閱讀:217 作者:Leah 欄目:編程語言

今天就跟大家聊聊有關怎么在Java中利用Clone實現深拷貝與淺拷貝,可能很多人都不太了解,為了讓大家更加了解,小編給大家總結了以下內容,希望大家根據這篇文章可以有所收獲。

package com.lxk.model;

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<Car> {
 private String sign;
 private int price;
 private List<Dog> myDog;
 private List<String> boys;
 public Car() {
 }
 public Car(String sign, int price) {
 this.sign = sign;
 this.price = price;
 }
 public Car(String sign, int price, List<Dog> myDog) {
 this.sign = sign;
 this.price = price;
 this.myDog = myDog;
 }
 public Car(String sign, int price, List<Dog> myDog, List<String> 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<Dog> getMyDog() {
 return myDog;
 }
 public void setMyDog(List<Dog> myDog) {
 this.myDog = myDog;
 }
 public List<String> getBoys() {
 return boys;
 }
 public void setBoys(List<String> 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
 * <p>
 * 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);//再次輸出看修改的結果
 }
}

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

怎么在Java中利用Clone實現深拷貝與淺拷貝

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

我們可能覺得自己在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;
 }

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

怎么在Java中利用Clone實現深拷貝與淺拷貝

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

怎么舉一反三?

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

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

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

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

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

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

 /**
 * 對象的深度克隆,此處的對象涉及Collection接口和Map接口下對象的深度克隆
 * 利用序列化和反序列化的方式進行深度克隆對象
 *
 * @param object 待克隆的對象
 * @param <T> 待克隆對象的數據類型
 * @return 已經深度克隆過的對象
 */
 public static <T extends Serializable> 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是什么

Java是一門面向對象編程語言,可以編寫桌面應用程序、Web應用程序、分布式系統和嵌入式系統應用程序。

看完上述內容,你們對怎么在Java中利用Clone實現深拷貝與淺拷貝有進一步的了解嗎?如果還想了解更多知識或者相關內容,請關注億速云行業資訊頻道,感謝大家的支持。

向AI問一下細節

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

AI

永德县| 郯城县| 孟州市| 中卫市| 昌吉市| 潼南县| 宁化县| 新巴尔虎右旗| 怀集县| 顺昌县| 鸡东县| 镇坪县| 宁化县| 大方县| 龙口市| 威宁| 讷河市| 信宜市| 轮台县| 西盟| 定兴县| 卓尼县| 金塔县| 伊通| 景泰县| 尤溪县| 乌兰察布市| 中牟县| 金溪县| 额尔古纳市| 沭阳县| 满洲里市| 大化| 甘泉县| 山东省| 通辽市| 文昌市| 木兰县| 天等县| 交口县| 中牟县|