Java的賦值、淺克隆和深度克隆的區別


賦值 直接  = ,克隆 clone

假如說你想復制一個簡單變量。很簡單:

int a= 5;  
int b= a;  

b = 6;

這樣 a == 5, b == 6

不僅僅是int類型,其它七種原始數據類型(boolean,char,byte,short,float,double.long)同樣適用於該類情況。

但是如果你復制的是一個對象、list集合的情況下,情況就有些復雜了。

 

class Student {  
    private int number;  
  
    public int getNumber() {  
        return number;  
    }  
  
    public void setNumber(int number) {  
        this.number = number;  
    }  
      
}  
public class Test {  
      
    public static void main(String args[]) {  
        Student stu1 = new Student();  
        stu1.setNumber(12345);  
        Student stu2 = stu1;  
          
        System.out.println("學生1:" + stu1.getNumber());  
        System.out.println("學生2:" + stu2.getNumber());  
    }  
}



結果: 學生1:12345  
學生2:12345  

 

這就怪了,為什么改變學生2的學號,學生1的學號也發生了變化呢?

原因出在(stu2 = stu1) 這一句。該語句的作用是將stu1的引用賦值給stu2,

這樣,stu1和stu2指向內存堆中同一個對象。如圖:

 

 

 

 

 

要做到 賦值的兩個對象之間的內存地址重新定義

實現對象克隆有兩種方式:

  1). 實現Cloneable接口並重寫Object類中的clone()方法;

class Address implements Cloneable {  
    private String add;  
  
    public String getAdd() {  
        return add;  
    }  
  
    public void setAdd(String add) {  
        this.add = add;  
    }  
      
    @Override  
    public Object clone() {              // 下面 這個是重點
        Address addr = null;  
        try{  
            addr = (Address)super.clone();  
        }catch(CloneNotSupportedException e) {  
            e.printStackTrace();  
        }  
        return addr;  
    }  
}  

 

2). 實現Serializable接口,通過對象的序列化和反序列化實現克隆,可以實現真正的深度克隆。

如果引用類型里面還包含很多引用類型,或者內層引用類型的類里面又包含引用類型,使用clone方法就會很麻煩。這時我們可以用序列化的方式來實現對象的深克隆。

public class Outer implements Serializable{
  private static final long serialVersionUID = 369285298572941L;  //最好是顯式聲明ID
  public Inner inner;
 //Discription:[深度復制方法,需要對象及對象所有的對象屬性都實現序列化] 
  public Outer myclone() {
      Outer outer = null;
      try { // 將該對象序列化成流,因為寫在流里的是對象的一個拷貝,而原對象仍然存在於JVM里面。所以利用這個特性可以實現對象的深拷貝
          ByteArrayOutputStream baos = new ByteArrayOutputStream();
          ObjectOutputStream oos = new ObjectOutputStream(baos);
          oos.writeObject(this);
      // 將流序列化成對象
          ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
          ObjectInputStream ois = new ObjectInputStream(bais);
          outer = (Outer) ois.readObject();
      } catch (IOException e) {
          e.printStackTrace();
      } catch (ClassNotFoundException e) {
          e.printStackTrace();
      }
      return outer;
  }
}

 

 

實現對象克隆有兩種方式:

  1). 實現Cloneable接口並重寫Object類中的clone()方法;

  2). 實現Serializable接口,通過對象的序列化和反序列化實現克隆,可以實現真正的深度克隆。

注意:基於序列化和反序列化實現的克隆不僅僅是深度克隆,更重要的是通過泛型限定,可以檢查出要克隆的對象是否支持序列化,這項檢查是編譯器完成的,不是在運行時拋出異常,這種是方案明顯優於使用Object類的clone方法克隆對象。讓問題在編譯的時候暴露出來總是優於把問題留到運行時。

注: 集合的clone,ArrayList 默認實現了cloneable,但是List<A> A對象不是深度克隆,A對象的內容也是使用同一個內存地址,所以A對象也必須實現clone

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM