プロトタイプ・モードの浅いレプリケーション(浅いレプリケーション)と深いレプリケーション(深いレプリケーション)の詳細

26855 ワード

前言
プロトタイプ・モードの浅いレプリケーションと深いレプリケーションといえば、浅いレプリケーションは値タイプのメンバー変数をレプリケーションし、参照タイプの変数は参照のみをレプリケーションし、実際には2つのオブジェクトが同じインスタンスを指していることがわかります.深いレプリケーションは、値タイプのメンバー変数だけでなく、参照タイプのメンバー変数に対してストレージスペースを申請し、新しいオブジェクトにします.言ったことはすべて间违っていないで、远くこれらがまだ足りないことを知っていて、私达はその原理がこの2つの言叶を证明することを理解して、以下に彼らの実现の过程を言います!
浅いレプリケーション
浅いレプリケーションは、次の2つのステップに分けられます.
1.Cloneableインタフェースを実装するには、ソースコードを見てみましょう.このインタフェースには方法がありません.彼の役割は、実行時に仮想マシンがこのインタフェースを実装したクラスでclone()メソッドを安全に使用できることを通知することです.Java仮想マシンでは、このインタフェースを実現したクラスのみがコピーできます.2.Objectクラスはcloneメソッドを提供してくれたので、cloneメソッドを書き直して浅いレプリケーションを実現しました.
コード#コード#
public class Sheep implements Cloneable {
    private String name;
    private int age;
    private String color;
    private Sheep friend;
	//    get set tostring       
    @Override
    protected Object clone() {
        Sheep sheep = null;
        try {
            sheep = (Sheep) super.clone();
        } catch (Exception e) {
            System.out.println(e.getMessage());
        }
        return sheep;
    }
}


クライアントはこのようなコードを実行します
    public static void main(String[] args) throws CloneNotSupportedException {
        Sheep sheep = new Sheep("tom",1,"  ");
        sheep.setFriend(new Sheep("jack",2,"  "));
        Sheep sheep2 = (Sheep)sheep.clone();
        System.out.println(sheep.hashCode()); //      356573597
        System.out.println(sheep2.hashCode()); //      1735600054
    }

出力結果から、2つのオブジェクトが同じではないことがわかります.これは、値タイプのメンバー変数がコピーされていることを示しています.次に、このようなコードを見てみましょう.
    public static void main(String[] args) throws CloneNotSupportedException {
        Sheep sheep = new Sheep("tom",1,"  ");
        sheep.setFriend(new Sheep("jack",2,"  "));
        Sheep sheep2 = (Sheep)sheep.clone();
        System.out.println(sheep.getFriend().hashCode());//      356573597
        System.out.println(sheep2.getFriend().hashCode());//      356573597
    }

出力結果から、2つのオブジェクトの参照タイプfriendは同じであり、浅いコピーはアプリケーションタイプに対して参照をコピーしただけで、新しいストレージ領域を開いていないことがわかります.
深くコピー
深いレプリケーションを実現するには、次の2つの方法があります.
  • 方式一:cloneメソッド(Cloneableインタフェースを実装する必要がある)
  • を使用する
  • 方式一:オブジェクトのシーケンス化による実装(Serializableインタフェースの実装が必要)
  • の使用を推奨する.
    方式一
    コード#コード#
    public class DeepProtoType implements Serializable, Cloneable {
        private String name;
        private DeepCloneableTarget deepCloneableTarget;
    	//get set         
        //   -   1   clone  
        @Override
        protected Object clone() throws CloneNotSupportedException {
            Object deep = null;
            //          String   
            deep = super.clone();
            //        ,      
            DeepProtoType deepProtoType = (DeepProtoType) deep;
            deepProtoType.deepCloneableTarget = (DeepCloneableTarget) deepCloneableTarget.clone();
            return deep;
        }
    }
    

    このクラスは現実を助けるために
    public class DeepCloneableTarget implements Serializable,Cloneable {
        private String cloneName;
        public DeepCloneableTarget(String cloneName) {
            this.cloneName = cloneName;
        }
        @Override
        protected Object clone() throws CloneNotSupportedException {
            return super.clone();
        }
    }
    

    クライアントコード
        public static void main(String[] args) throws CloneNotSupportedException {
            DeepProtoType p = new DeepProtoType();
            p.setName("  ");
            p.setDeepCloneableTarget(new DeepCloneableTarget("  "));
            //         
            DeepProtoType p2 = (DeepProtoType) p.clone();
            System.out.println(p.getDeepCloneableTarget().hashCode()); //    356573597
            System.out.println(p2.getDeepCloneableTarget().hashCode()); //    1735600054
        }
    

    出力結果から、2つのオブジェクトの参照タイプのメンバー変数は同じではなく、深いレプリケーションに成功したことを証明する新しいオブジェクトであることがわかります.
    方式2
    コード#コード#
    public class DeepProtoType implements Serializable, Cloneable {
        private String name;
        private DeepCloneableTarget deepCloneableTarget;
    	//get set         
    	//     -  2           (  )
        public Object deepClone() {
            //     
            ByteArrayOutputStream bos = null;
            ObjectOutputStream oos = null;
            ByteArrayInputStream bis = null;
            ObjectInputStream ois = null;
            try {
                //   
                bos = new ByteArrayOutputStream();
                oos = new ObjectOutputStream(bos);
                oos.writeObject(this);
                //    
                bis = new ByteArrayInputStream(bos.toByteArray());
                ois = new ObjectInputStream(bis);
                DeepProtoType o = (DeepProtoType) ois.readObject();
                return o;
            } catch (Exception e) {
                e.printStackTrace();
                return null;
            } finally {
                try {
                    bos.close();
                    oos.close();
                    bis.close();
                    ois.close();
                } catch (Exception e2) {
                    System.out.println(e2.getMessage());
                }
            }
        }
    }
    

    クライアントコードは、私たちが書いたdeepCloneメソッド領域を使用してオブジェクトをコピーします.
        public static void main(String[] args) throws CloneNotSupportedException {
            DeepProtoType p = new DeepProtoType();
            p.setName("  ");
            p.setDeepCloneableTarget(new DeepCloneableTarget("  "));
            //         
            DeepProtoType p2 = (DeepProtoType) p.deepClone();
            System.out.println(p.getDeepCloneableTarget().hashCode()); //    621009875
            System.out.println(p2.getDeepCloneableTarget().hashCode()); //    2065951873
        }
    

    出力結果から分かるように、2つのオブジェクトの参照タイプのメンバー変数は異なり、深いレプリケーションに成功したことが証明されます.
    まとめ
    2つの方法で深いレプリケーションを実現するには、2つ目の方法をお勧めします.なぜかというと、1つのクラスの参照タイプが多い場合、1つの方法は1つの処理が必要で、2つ目の方法は1回の処理で、2つ目の方法は便利です.もし本文に疑問があるところがあれば、伝言を歓迎して一緒に勉強して、もしあなたの疑問を解決したら、「いいね」をクリックして支持しましょう.