Java-クローン実装方式の深いクローンと浅いクローン

8216 ワード

クローンの概要
クローンは文字通りコピーですね.私たちは普段、値タイプのデータをコピーして直接コピーすればいいのですが、オブジェクトなどの参照タイプをコピーするときは手がつけられません.値を付与するには参照しかできないので、手動で操作して中の値を取り出して新しいオブジェクトに割り当てるのは面倒です.いい方法はありませんか.JAvaはcloneを提供しています.
クローンの種類
Java言語では、データ型は値タイプに分けられます(基本データ型)と参照タイプ.値タイプはint、double、byte、boolean、charなどの単純なデータ型を含み、参照タイプはクラス、インタフェース、配列などの複雑なタイプを含む.浅いクローンと深いクローンの主な違いは、潜在的なクローン複製の際に値クラス型であれば直接クローンし、参照タイプであればオブジェクト参照のオブジェクトはクローンされず、単にこの参照を簡単にコピーします.つまり、クローンされたオブジェクトの参照タイプデータを変更すると、同じメモリを指しているため、元のオブジェクトでも変更されます.深いクローンはクローン化されます.
浅いクローン1.コピーされたクラスは、タグインタフェース(いかなる方法も含まない)2であるClonenableインタフェースを実装する必要がある.clone()メソッドを上書きし、アクセス修飾子をpublicに設定します.メソッドでsuperを呼び出す.clone()メソッドは、必要なレプリケーションオブジェクトを取得します.3.コピーされたオブジェクトを返す
class Student implements Cloneable{  
    private int number;  

    public int getNumber() {  
        return number;  
    }  

    public void setNumber(int number) {  
        this.number = number;  
    }  

    @Override  
    public Object clone() {  
        Student stu = null;  
        try{  
            stu = (Student)super.clone();  
        }catch(CloneNotSupportedException e) {  
            e.printStackTrace();  
        }  
        return stu;  
    }  
}  

深いクローンの前の2つのステップと浅いクローンの差は多くない後のステップとは異なる.コピーされたクラスは、タグインタフェース(いかなる方法も含まない)2であるClonenableインタフェースを実装する必要がある.clone()メソッドを上書きし、アクセス修飾子をpublicに設定します.メソッドでsuperを呼び出す.clone()メソッドは、必要なレプリケーションオブジェクトを取得します.3.コピーされたオブジェクトを返します.オブジェクトにリファレンスオブジェクトがある場合は、リファレンスオブジェクトをもう一度クローンします.
class Student implements Cloneable{  
    private int number;  
    private ArrayList image = new ArrayList();
    public int getNumber() {  
        return number;  
    }  
   public int getImage() {  
        return image;  
    } 
    public void setNumber(int number) {  
        this.number = number;  
    }  
       public void setImage(String url) {  
        this.image.add(url);  
    } 
    @Override  
    public Object clone() {  
        Student stu = null;  
        try{  
            stu = (Student)super.clone();  

            //        
            stu.image=this.image.clone();
        }catch(CloneNotSupportedException e) {  
            e.printStackTrace();  
        }  
        return stu;  
    }  
}  

もちろん、このような深いクローン方式には欠陥があります.参照オブジェクトがたくさんある場合、あるいは参照カバーが多くの重さを参照している場合、例えばimageはオブジェクトであり、オブジェクトの中に参照オブジェクトがある場合は、面倒です.
多層クローン問題を解決するためにシーケンス化された方法でオブジェクトの深いクローンを実現しますが、シーケンス化が分かれば理解しやすくなります.前の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;
   }
 }

中のcloneクラスで使われているinnerクラスもSerializableを実装しなければならない.そうしないとシーケンス化できない.
public class Inner implements Serializable{
 2   private static final long serialVersionUID = 872390113109L; //       ID
 3   public String name = "";
 4 
 5   public Inner(String name) {
 6       this.name = name;
 7   }
 8 
 9   @Override
10   public String toString() {
11       return "Inner name  :" + name;
12   }
13 }

また、シーケンス化と逆シーケンス化に基づいて実現されるクローンは、深度クローンだけでなく、汎用的な限定により、クローンするオブジェクトがシーケンス化をサポートしているかどうかを確認することができます.このチェックはコンパイラが完了し、実行時に異常を投げ出すのではなく、Objectクラスのcloneメソッドを使用してオブジェクトをクローンするよりも明らかに優れています.問題をコンパイル時に露出させるのは、常に実行時に問題を残すよりも優れている.
まとめ
具体的には、そのクローン方式は実際の状況によって異なり、それぞれの方法にはメリットとデメリットがあり、適用状況も異なり、シーケンス化を使用すると前の2つと比較してメモリを消費しますが、多層クローンの問題をよりよく解決し、実際のシーンでクローンが必要なオブジェクトが値タイプであれば浅いクローンを使用すればいいのです.上の配列のような単一の参照オブジェクトが含まれている場合は、単純な深クローンでよく、多層の場合はシーケンス化が使用されます.