程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> JAVA編程 >> 關於JAVA >> Java 深拷貝與淺拷貝的剖析

Java 深拷貝與淺拷貝的剖析

編輯:關於JAVA

Java 深拷貝與淺拷貝的剖析。本站提示廣大學習愛好者:(Java 深拷貝與淺拷貝的剖析)文章只能為提供參考,不一定能成為您想要的結果。以下是Java 深拷貝與淺拷貝的剖析正文


在正式的進入主題之前,我們先來懂得下深拷貝和前拷貝的概念:

淺拷貝:

會創立一個新對象,這個對象有著原始對象屬性值的一份准確拷貝,假如屬性是根本類型,拷貝的是根本類型的值;假如屬性是內存地址,拷貝的就是內存地址,是以假如一個對象轉變了這個地址就會影響到另外一個對象;

深拷貝:

不只要復制對象的一切非援用成員變量值,還要為援用類型的成員變量創立新的實例,而且初始化為情勢參數實例值;

懂得完概念以後,我們來測試下通俗的對象賦值操作屬於深拷貝照樣淺拷貝:

測試代碼:

public class DepthCopy { 
  public static void main(String[] args) { 
    Copy first = new Copy("hzw", 24); 
    Copy second = first; 
    second.name = "shanxi"; 
    System.out.println(first.name);//輸入shanxi 
  } 
} 
class Copy 
{ 
  public String name; 
  public int age; 
  public Copy(String name,int age) { 
    this.name = name; 
    this.age = age; 
  } 
} 

可以發明,在second將name屬性值修正為shanxi以後,first的name屬性值也釀成了shanxi,這點便可以看出通俗的對象賦值屬於淺拷貝;

明確了對象之間賦值是淺拷貝以後,接上去我們來看看克隆究竟是深拷貝照樣淺拷貝,測試代碼是讓下面的Copy對象完成Cloneable接口外面的clone辦法:

public class DepthCopy { 
  public static void main(String[] args) { 
    Copy first = new Copy("hzw", 24); 
    Copy second = null; 
    try { 
      second = (Copy) first.clone(); 
    } catch (CloneNotSupportedException e) { 
      e.printStackTrace(); 
    } 
    second.name = "shanxi"; 
    System.out.println(first.name);//輸入: hzw 
    System.out.println(first);//輸入: com.hzw.day33.Copy@7f39ebdb 
    System.out.println(second);//輸入: com.hzw.day33.Copy@33abb81e 
  } 
} 
class Copy implements Cloneable 
{ 
  public String name; 
  public int age; 
  public Copy(String name,int age) { 
    this.name = name; 
    this.age = age; 
  } 
  @Override 
  protected Object clone() throws CloneNotSupportedException { 
    return super.clone(); 
  } 
} 

可以看出本來創立出的對象first和克隆創立出的對象second是兩個實例,是以關於second中name屬性的修正其實不會影響first中的name屬性;然則,我們其實不能純真的以為克隆就是深拷貝的,好比上面這個例子:

public class DepthCopy { 
  public static void main(String[] args) { 
    Student student = new Student(95); 
    Copy first = new Copy("hzw", 24,student); 
    Copy second = null; 
    try { 
      second = (Copy) first.clone(); 
    } catch (CloneNotSupportedException e) { 
      e.printStackTrace(); 
    } 
    second.name = "shanxi"; 
    second.student.score = 60; 
    System.out.println(first == second);//false 
    System.out.println(first.student == second.student);//true 
    System.out.println(first.student.score);//60 
  } 
} 
class Copy implements Cloneable 
{ 
  public String name; 
  public int age; 
  public Student student; 
  public Copy(String name,int age,Student student) { 
    this.name = name; 
    this.age = age; 
    this.student = student; 
  } 
  @Override 
  protected Object clone() throws CloneNotSupportedException { 
    return super.clone(); 
  } 
} 
class Student  
{ 
  public int score; 
  public Student(int score) { 
    this.score = score; 
  } 
} 

看到沒有呢?我們經由過程克隆的方法創立了second,很顯著發明first和second是兩個實例,由於first == second輸入為false,然則first和second外面的student對象倒是一樣的,經由過程second修正了student的score值以後,first外面student的score也產生了轉變,這也就是說first和second外面的student是雷同的,這也就解釋了克隆是淺拷貝的,我們要想完成克隆的深拷貝,必需讓Copy對象外面的Student對象也要完成Cloneable接口外面的clone辦法,而且在Copy外面的克隆辦法前往Student的一個克隆便可,如許便可以包管Student的獨一啦,修正以後的代碼以下:

public class DepthCopy { 
  public static void main(String[] args) { 
    Student student = new Student(95); 
    Copy first = new Copy("hzw", 24,student); 
    Copy second = null; 
    try { 
      second = (Copy) first.clone(); 
    } catch (CloneNotSupportedException e) { 
      e.printStackTrace(); 
    } 
    second.name = "shanxi"; 
    second.student.score = 60; 
    System.out.println(first == second);//false 
    System.out.println(first.student == second.student);//false 
    System.out.println(first.student.score);//95 
    System.out.println(second.student.score);//60 
  } 
} 
class Copy implements Cloneable 
{ 
  public String name; 
  public int age; 
  public Student student; 
  public Copy(String name,int age,Student student) { 
    this.name = name; 
    this.age = age; 
    this.student = student; 
  } 
  @Override 
  protected Object clone() throws CloneNotSupportedException { 
    Copy copy = (Copy)super.clone(); 
    copy.student = (Student) student.clone(); 
    return copy; 
  } 
} 
class Student implements Cloneable 
{ 
  public int score; 
  public Student(int score) { 
    this.score = score; 
  } 
  @Override 
  protected Object clone() throws CloneNotSupportedException { 
    return super.clone(); 
  } 
} 

可以看到此時first和second和first.student和second.student都不是雷同的,是以我們修正second的student的score以後並沒有影響到first裡的student的score值,到達了深拷貝的目標;

然則,細心一想成績就出來了,假設我們下面例子的Student類中也存在援用類型的屬性,好比College類,那末我們必需讓College類完成Cloneable接口,然後在Student類外面的clone辦法外面挪用College類的clone辦法,在Copy類的clone辦法中挪用Student類的clone辦法,發明沒有了,這個進程好龐雜,必需讓類中的有關援用類型全體完成Cloneable接口,感到好費事是否是,好的,接上去就該牛人退場了;

處理深拷貝成績最好的方法就是采取序列化方法,如許各類類均不消完成Cloneable接口的,直接序列化反序列化便可以啦,我們來見識下吧。

import java.io.File; 
import java.io.FileInputStream; 
import java.io.FileOutputStream; 
import java.io.ObjectInputStream; 
import java.io.ObjectOutputStream; 
import java.io.Serializable; 
 
public class DepthCopy { 
  public static void main(String[] args) { 
    College school = new College("nongda"); 
    Student student = new Student(95, school); 
    Copy copy = new Copy("hzw",23, student); 
    Copy another = null;//表現反序列化出來的類實例 
    //停止序列化操作 
    try { 
      FileOutputStream fos = new FileOutputStream(new File("d:/copy.txt")); 
      ObjectOutputStream oos = new ObjectOutputStream(fos); 
      oos.writeObject(copy); 
    } catch (Exception e) { 
      e.printStackTrace(); 
    } 
    //停止反序列化操作 
    FileInputStream fis; 
    try { 
      fis = new FileInputStream(new File("d:/copy.txt")); 
      ObjectInputStream ois = new ObjectInputStream(fis); 
      another = (Copy) ois.readObject(); 
    } catch (Exception e) { 
      e.printStackTrace(); 
    } 
    System.out.println(copy == another);//false 
    System.out.println(copy.student == another.student);//false 
    System.out.println(copy.student.school == another.student.school);//false 
    another.student.school.schoolName = "wuda"; 
    System.out.println(copy.student.school.schoolName);//nongda 
  } 
} 
class Copy implements Serializable 
{ 
  public String name; 
  public int age; 
  public Student student; 
  public Copy(String name,int age,Student student) { 
    this.name = name; 
    this.age = age; 
    this.student = student; 
  } 
} 
class Student implements Serializable 
{ 
  public int score; 
  public College school; 
  public Student(int score,College school) { 
    this.score = score; 
    this.school = school; 
  } 
} 
class College implements Serializable 
{ 
  public String schoolName; 
  public College(String schoolName) { 
    this.schoolName = schoolName; 
  } 
} 

從輸入便可以看出來,反序列化以後生成的對象完整就是對原對象的一份拷貝,除屬性值雷同以外其實不和原對象有任何干系,是以當我們修正反序列化生成對象的schoolName為"wuda"的時刻並沒有修正本來實例的schoolName值,照樣輸入"nongda",是以到達了真實的深拷貝後果,然則要想完成序列化,一切的有關類都必需完成Serializable接口,這總也比既完成Cloneable接口又完成clone辦法更便利吧。

以上就是對Java 深拷貝和淺拷貝的具體講授,有須要的可以參考下。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved