JAvaにおけるcloneの学習

5361 ワード

今日はeffective javaの中のcloneの使用を見て、それについて少し理解して、以下は自分の理解したことを書いて、後で運用するために~~~~
JAvaでオブジェクトのコピーを実装するには、Objectのclone()メソッド、自分の書いたクラスに対してcloneableインタフェースを実装し、親クラスのclone()メソッドを上書きすることができます.
従来のオブジェクトには次のような値が割り当てられています.

public class Test{
    private String str;
    public Test(String str){
        this.str = str;
    }
    public void setStr(String str){
        this.str = str;
    }
    public String getStr(){
        return this.str;
    }
    public static void main(String args[]){
        Test t1 = new Test("www");
        Test t2 = t1;
        t2.setStr("ddd");
        System.out.println(t1.getStr());//  ddd
        System.out.println(t2.getStr());//  ddd
    }
}

上のt 2=t 1は、t 1とt 2を同時に同じメモリに向けただけで、t 2の変更にもt 1に影響しますが、t 2の変更がt 1に影響しないとしたらどうすればいいのでしょうか.
実はとても简単で、これはObject类のclone()方法を使うことができて、同时にCloneableインタフェースの改善したコードを実现して、以下の通りです:

public class Test implements Cloneable{
    private String str;
    public Test(String str){
        this.str = str;
    }
    public void setStr(String str){
        this.str = str;
    }
    public String getStr(){
        return this.str;
    }
    public static void main(String args[]) throws CloneNotSupportedException{
        Test t1 = new Test("www");
        Test t2 = (Test) t1.clone();
        t2.setStr("ddd");
        System.out.println(t1.getStr());//  www
        System.out.println(t2.getStr());//  ddd
    }
}

このようにt 2は新しいオブジェクト参照であり、Test t 2=new Test(「www」)と同様に、t 1とt 2は異なるメモリ空間を指し、t 2の設定値はt 1に影響しない.
しかし、このようにするともう一つの問題が発生します.次のコードを見てください.

public class Test implements Cloneable{
    private String str;
    private HashMap<Integer, String> map = new HashMap<Integer, String>();
    public Test(String str){
        this.str = str;
        map.put(1, "1111");
        map.put(2, "2222");
        map.put(3, "3333");
    }
    public void setStr(String str){
        this.str = str;
    }
    public String getStr(){
        return this.str;
    }
    public HashMap<Integer, String> getMap(){
    	return this.map;
    }
    public static void main(String args[]) throws CloneNotSupportedException{
        Test t1 = new Test("www");
        Test t2 = (Test) t1.clone();
        t2.setStr("ddd");
        System.out.println(t1.getStr());//  www
        System.out.println(t2.getStr());//  ddd
        
        t2.getMap().put(4, "4444");
        System.out.println(t1.getMap().get(4));//  4444(         null)
        System.out.println(t2.getMap().get(4));//  4444
    }
}

上のt 1の出力はnullではなく4444であることがわかりますが、これはなぜでしょうか??
実はObjectクラスのclone()メソッドは、上のプログラムのように、t 1とt 2のmapメンバー変数が指すメモリアドレスが同じであるため、いずれかの内部要素の値が同じオブジェクトをコピーすることで、同じメモリ空間を指さないようにすることができますが、mapのキー値を変更すると、彼ら2人は同時に同じ空間を指しており、1つは変化し、もう1つは変化します.
解決策は次のとおりです.

public class Test implements Cloneable{
    private String str;
    private HashMap<Integer, String> map = new HashMap<Integer, String>();
    public Test(String str){
        this.str = str;
        map.put(1, "1111");
        map.put(2, "2222");
        map.put(3, "3333");
    }
    public void setStr(String str){
        this.str = str;
    }
    public String getStr(){
        return this.str;
    }
    public HashMap<Integer, String> getMap(){
    	return this.map;
    }
    
    public static void main(String args[]) throws CloneNotSupportedException{
        Test t1 = new Test("www");
        Test t2 = (Test) t1.clone();
        t2.setStr("ddd");
        
        System.out.println(t1.getStr());//  www
        System.out.println(t2.getStr());//  ddd
        
        t2.getMap().put(4, "4444");
        System.out.println(t1.getMap().get(4));//  null
        System.out.println(t2.getMap().get(4));//  4444
    }
    
    @Override public Test clone(){
    	Test obj = null;
    	try {
    		obj = (Test) super.clone();
    		obj.map = (HashMap<Integer, String>) obj.map.clone();
		} catch (CloneNotSupportedException e) {
			e.printStackTrace();
		}
		return obj;
    }
}

clone()メソッドを書き換え、メンバー変数もclone()1部にすることで、上記の問題を解決することができ、オブジェクト配列もこのように処理されます.実際には、あなたが使用しているオブジェクトのclone()メソッドであれば、clone()メソッドを書き換えることが望ましいです.

    @Override public Test clone(){
    	Test obj = null;
    	try {
    		obj = (Test) super.clone();
                //clone       
		} catch (CloneNotSupportedException e) {
			e.printStackTrace();
		}
		return obj;
    }

まあ、なんとか書き終わったけど、JDKの中のcloneという方法にはいろいろ問題があったので、たくさんの牛たちはお勧めしないので、基本的な問題は後でゆっくり発掘しておきました~~~