克隆的理解

一、Cloneable 的用途 
Cloneable和Serializable一樣都是標記型接口,它們內部都沒有方法和屬性,implements Cloneable表示該對象能被克隆,能使用Object.clone()方法。如果沒有implements Cloneable的類調用Object.clone()方法就會拋出CloneNotSupportedException。

二、克隆的分類
1、淺克隆(shallow clone
     拷貝對象的時候僅僅拷貝對象本身和對象中的基本變量,而不拷貝對象中包含的引用所指向的對象。
2、深克隆(deep clone
     拷貝對象的時候不僅僅拷貝對象本身,同時拷貝對象所包含的的引用所指向的對象。
舉例說明:
對象A1中包含對B1的引用,B1中包含對C1的引用。
淺拷貝A1得到A2,A2中依然包含對B1的引用,B1中依然包含對C1的引用。深拷貝則是對淺拷貝的遞歸,深拷貝A1得到A2,A2中包含對B2(B1的copy)的引用,B2中包含對C2(C1的copy)的引用。 

三、克隆的舉例
要讓一個對象進行克隆,其實就是兩個步驟: 
      1、讓類實現java.lang.Cloneable接口
      2、重寫(override) Object類的clone()方法
代碼實現:
package com.tyxh.create;

public class Wife implements Cloneable {
     private int id;
     private String name;

     public int getId() {
           return id;
     }

     public void setId( int id) {
           this. id = id;
     }

     public String getName() {
           return name;
     }

     public void setName(String name) {
           this. name = name;
     }

     public Wife( int id,String name) {
           this. id = id;
           this. name = name;
     }

     @Override
     public int hashCode() {
           final int prime = 31;
           int result = 1;
          result = prime * result + id;
          result = prime * result + (( name == null) ? 0 : name.hashCode());
           return result;
     }
     
     @Override
     public boolean equals (Object obj) {
           if ( this == obj)
               return true;
           if (obj == null)
               return false;
           if (getClass() != obj.getClass())
               return false;
          Wife other = (Wife) obj;
           if ( id != other. id)
               return false;
           if ( name == null) {
               if (other. name != null)
                    return false;
          } else if (! name.equals(other. name))
               return false;
           return true;
     }

     @Override
     public Object clone() throws CloneNotSupportedException {
           return super.clone();
     }

     public static void main(String[] args) throws CloneNotSupportedException {
          Wife wife = new Wife(1, "wang");
          Wife wife2 = null;
          wife2 = (Wife) wife.clone();
          System. out.println( "wife  : " + wife);
          System. out.println( "wife2 : " + wife2);
          wife.setName( "tyxh");
          System. out.println( "wife  : " + wife);
          System. out.println( "wife2 : " + wife2);
          wife2.setName( "sotaof");
          System. out.println( "wife  : " + wife);
          System. out.println( "wife2 : " + wife2);
           //上面兩個輸出的地址相同,克隆的只是引用
          System. out.println( "class same="+(wife.getClass()==wife2.getClass())); //true
          System. out.println( "object same="+(wife==wife2));//false 說明兩個對象的地址不同
          System. out.println( "object equals="+(wife.equals (wife2)));//false
     }
}

輸入結果:
wife  : com.tyxh.create.Wife@3795e3
wife2 : com.tyxh.create.Wife@3795e3
wife  : com.tyxh.create.Wife@369415
wife2 : com.tyxh.create.Wife@3795e3
wife  : com.tyxh.create.Wife@369415
wife2 : com.tyxh.create.Wife@ca8fb940
class same=true
object same=false
object equals=false

第一行和第二行相同的原因不是因爲克隆後的wife和wife2地址相同,而是因爲hashcode的緣故,我們注意hashcode的返回值result = prime * result + (( name == null) ? 0 : name.hashCode());name變化的話,返回值就會發生改變。如果你在hashcode方法中返回1,那麼結果就會是@1;

當對wife的name值進行修改之後,wife的值變化了,而wife2的值沒有變化;

當對wife2的name值進行修改之後,wife2的值變化了,而wife的值沒有變化

但是這並不代表wife和wife2的地址發生了改變,這僅僅能說明wife和wife2的值發生了改變。當我們註釋掉hashCode()和equals()方法之後,再看一下輸出結果:

wife  : com.tyxh.create.Wife@3771ed5e
wife2 : com.tyxh.create.Wife@1896d2c2
wife  : com.tyxh.create.Wife@3771ed5e
wife2 : com.tyxh.create.Wife@1896d2c2
wife  : com.tyxh.create.Wife@3771ed5e
wife2 : com.tyxh.create.Wife@1896d2c2
class same=true
object same=false
object equals=false

通過結果可以看出,不管是對wife還是對wife2進行值的修改,它們的地址都沒有改變。

四.淺克隆的舉例 
package com.tyxh.create;

public class Husband implements Cloneable {
     private int id;
     private Wife wife;
     
     public Wife getWife() {
           return wife;
     }

     public void setWife(Wife wife) {
           this. wife = wife;
     }

     public int getId() {
           return id;
     }

     public void setId( int id) {
           this. id = id;
     }

     public Husband( int id) {
           this. id = id;
     }

     @Override
     public int hashCode() { 
           final int prime = 31;
           int result = 1;
          result = prime * result + id;
           return result;
     }

     @Override
     protected Object clone() throws CloneNotSupportedException {
           return super.clone();
     }

     @Override
     public boolean equals(Object obj) {
           if ( this == obj)
               return true;
           if (obj == null)
               return false;
           if (getClass() != obj.getClass())
               return false;
          Husband other = (Husband) obj;
           if ( id != other. id)
               return false;
           return true;
     }

     /**
      * @param args
      * @throws CloneNotSupportedException
      */
     public static void main(String[] args) throws CloneNotSupportedException {
          Wife wife = new Wife(1, "jin");
          Husband husband = new Husband(1);
          Husband husband2 = null;
          husband.setWife(wife);
          husband2 = (Husband) husband.clone();
          System. out.println( "husband  : " + husband);
          System. out.println( "husband2 : " + husband2);
          System. out.println( "husband class same="+(husband.getClass()==husband2.getClass())); //true
          System. out.println( "husband object same="+(husband==husband2));//false
          System. out.println( "husband object equals="+(husband.equals(husband)));//true
          System. out.println( "wife class same="+(husband.getWife().getClass()==husband2.getWife().getClass())); //true
          System. out.println( "wife object same="+(husband.getWife()==husband2.getWife())); //true 說明引用是同一個引用
          System. out.println( "wife object equals="+(husband.getWife().equals(husband.getWife()))); //true
     }
}

輸入結果如下:
husband  : com.tyxh.create.Husband@20
husband2 : com.tyxh.create.Husband@20
husband class same=true
husband object same=false
husband object equals=true
wife class same=true
wife object same=true
wife object equals=true

四.深克隆的舉例 
package com.tyxh.create;

public class Husband implements Cloneable {
     private int id;
     private Wife wife;
     
     public Wife getWife() {
           return wife;
     }

     public void setWife(Wife wife) {
           this. wife = wife;
     }

     public int getId() {
           return id;
     }

     public void setId( int id) {
           this. id = id;
     }

     public Husband( int id) {
           this. id = id;
     }

     @Override
     public int hashCode() { //myeclipse 自動生成的
           final int prime = 31;
           int result = 1;
          result = prime * result + id;
           return result;
     }

     @Override
     protected Object clone() throws CloneNotSupportedException {
          Husband husband = (Husband) super.clone();
          husband. wife = (Wife) husband.getWife().clone();
           return husband;
     }

     @Override
     public boolean equals(Object obj) { //myeclipse 自動生成的
           if ( this == obj)
               return true;
           if (obj == null)
               return false;
           if (getClass() != obj.getClass())
               return false;
          Husband other = (Husband) obj;
           if ( id != other. id)
               return false;
           return true;
     }

     /**
      * @param args
      * @throws CloneNotSupportedException
      */
     public static void main(String[] args) throws CloneNotSupportedException {
          Wife wife = new Wife(1, "jin");
          Husband husband = new Husband(1);
          Husband husband2 = null;
          husband.setWife(wife);
          husband2 = (Husband) husband.clone();
          System. out.println( "husband  : " + husband);
          System. out.println( "husband2 : " + husband2);
          System. out.println( "husband class same="+(husband.getClass()==husband2.getClass())); //true
          System. out.println( "husband object same="+(husband==husband2));//false
          System. out.println( "husband object equals="+(husband.equals(husband)));//true
          System. out.println( "wife class same="+(husband.getWife().getClass()==husband2.getWife().getClass())); //true
          System. out.println( "wife object same="+(husband.getWife()==husband2.getWife())); //false 說明引用不是同一個引用
          System. out.println( "wife object equals="+(husband.getWife().equals(husband.getWife()))); //true
     }
}

輸出結果如下:
husband  : com.tyxh.create.Husband@20
husband2 : com.tyxh.create.Husband@20
husband class same=true
husband object same=false
husband object equals=true
wife class same=true
wife object same=false
wife object equals=true

五、通過反序列化克隆 (也是深克隆)
package com.tyxh.create;

import java.io.*;

public class BeanUtil {
     @SuppressWarnings( "unchecked")
     public static <T> T cloneTo(T src) {
          ByteArrayOutputStream memoryBuffer = new ByteArrayOutputStream();
          ObjectOutputStream out = null;
          ObjectInputStream in = null;
          T dist = null;
          
           try {
              out = new ObjectOutputStream(memoryBuffer);
              out.writeObject(src);
              out.flush();
              
              in = new ObjectInputStream( new ByteArrayInputStream(memoryBuffer.toByteArray()));
              dist = (T) in.readObject();
              
          } catch (Exception e) {
              e.printStackTrace();
          } finally {
               if(out != null) {
                    try {
                        out.close();
                   } catch (IOException e) {
                        e.printStackTrace();
                   }
              }
               if(in != null) {
                    try {
                        in.close();
                   } catch (IOException e) {
                        e.printStackTrace();
                   }
              }
          }
                   
           return dist;
     }
     
     public static void main(String[] args) {
          Husband husband = new Husband(1);
          Wife wife = new Wife(1, "jin");
          husband.setWife(wife);
          Husband husband2 = cloneTo(husband);
          System. out.println("husband class same="+(husband.getClass()==husband2.getClass())); //true
          System. out.println( "husband object same="+(husband==husband2));//false
          System. out.println("husband object equals="+(husband.equals(husband)));//true
          System. out.println("wife class same="+(husband.getWife().getClass()==husband2.getWife().getClass())); //true
          System. out.println("wife object same="+(husband.getWife()==husband2.getWife())); //false 說明引用不是同一個引用
          System. out.println("wife object equals="+(husband.getWife().equals(husband.getWife()))); //true
     }
}

輸出結果如下:
husband class same=true
husband object same=false
husband object equals=true
wife class same=true
wife object same=false
wife object equals=true

通過第二行可以看出,反序列化之後的husband2與husband不是同一個對象
通過第五行可以看出,反序列化屬於一種深克隆,因爲husband和husband2的wife對象不同


發佈了146 篇原創文章 · 獲贊 37 · 訪問量 93萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章