参照clone浅いclone深いcloneシーケンス化clone反射深いclone


JAvaコピーの問題は3つあります.まず、次のコードを見てください.
package com;
class Address implements Cloneable{
	String city;
	Address(String city){
		this.city=city;
	}
	public String getCity() {
		return city;
	}

	@Override
	public String toString() {
		return "Address [city=" + city + "]";
	}
	public void setCity(String city) {
		this.city = city;
	}
	@Override
	protected Object clone() throws CloneNotSupportedException {
		return super.clone();
	}
}
public class Employee implements Cloneable{
	String name;
	int salary;
	Address addr;
	public Employee(String name,int salary,Address city){
		this.name=name;
		this.salary=salary;
		this.addr=city;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public int getSalary() {
		return salary;
	}
	public void setSalary(int salary) {
		this.salary = salary;
	}
	public Address getAddr() {
		return addr;
	}
	public void setAddr(Address addr) {
		this.addr = addr;
	}
	@Override
	public String toString() {
		return "Employee [addr=" + addr + ", name=" + name + ", salary="
				+ salary + "]";
	}
	@Override
	protected Object clone() throws CloneNotSupportedException {
		Employee cloned=(Employee)super.clone();
		return cloned;
	}
	public static void main(String[] args) throws CloneNotSupportedException{ //
		 Employee e1=new Employee(" ",500,new Address("  ")); //Employee             
		 Employee e2=e1; //          
		 e2.setName(" ");//    e2    
		 e2.setSalary(1000);
		 e2.setAddr(new Address("  "));
		 System.out.println("e1:"+e1); //  e1   : Employee [addr=Address [city=  ], name= , salary=1000]     
		 System.out.println("e2:"+e1); //  e1   : Employee [addr=Address [city=  ], name= , salary=1000]
		 System.out.println("e1.getAddr()==e2.getAddr():"+(e1.getAddr()==e2.getAddr()));
		 System.out.println(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>");
		 
		 Employee e12=new Employee(" ",500,new Address("  ")); //Employee          
		 Employee e22=(Employee)e12.clone(); //       
		 e22.setName(" ");//    e2      
		 e22.setSalary(1000);
		 e22.setAddr(new Address("  "));
		 System.out.println("e12:"+e12); //  e1   : Employee [addr=Address [city=  ], name= , salary=500]
		 System.out.println("e22:"+e22); //  e1   : Employee [addr=Address [city=  ], name= , salary=1000]
		 System.out.println("e12.getAddr()==e22.getAddr():"+(e12.getAddr()==e22.getAddr()));
		 System.out.println(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>");
		 
		 Employee e13=new Employee(" ",500,new Address("  ")); //Employee          
		 Employee e23=(Employee)e13.clone(); //       
		 e23.setName(" ");//    e2      
		 e23.setSalary(1000);
		 e23.getAddr().setCity("  ");		 
		 System.out.println("e13:"+e13); //  e1   : Employee [addr=Address [city=  ], name= , salary=500]
		 System.out.println("e23:"+e23); //  e1   : Employee [addr=Address [city=  ], name= , salary=1000]
		 System.out.println("e13.getAddr()==e23.getAddr():"+(e13.getAddr()==e23.getAddr()));
	 }
}

1.参照コピー
 Employee e2=e1; //          
		 e2.setName(" ");//    e2    
		 e2.setSalary(1000);
		 e2.setAddr(new Address("  "));
		 System.out.println("e1:"+e1); //  e1   : Employee [addr=Address [city=  ], name= , salary=1000]     
		 System.out.println("e2:"+e1); //  e1   : Employee [addr=Address [city=  ], name= , salary=1000]
		 System.out.println("e1.getAddr()==e2.getAddr():"+(e1.getAddr()==e2.getAddr()));//true
e 1とe 2は同じオブジェクトを指します.
実行結果:
e1:Employee [addr=Address [city=  ], name= , salary=1000]
e2:Employee [addr=Address [city=  ], name= , salary=1000]
e1.getAddr()==e2.getAddr():true

2.浅いコピー:
 Employee e13=new Employee(" ",500,new Address("  ")); //Employee          
		 Employee e23=(Employee)e13.clone(); //       
		 e23.setName(" ");//    e2      
		 e23.setSalary(1000);
		 e23.getAddr().setCity("  ");		 
		 System.out.println("e13:"+e13); //  e1   : Employee [addr=Address [city=  ], name= , salary=500]
		 System.out.println("e23:"+e23); //  e1   : Employee [addr=Address [city=  ], name= , salary=1000]
		 System.out.println("e13.getAddr()==e23.getAddr():"+(e13.getAddr()==e23.getAddr()));//true

注意点:
1)クラスはインタフェースを実装する必要があります.そうしないとclone()メソッドが呼び出され、実行時にCloneNotSupportedExceptio異常が報告されます.
2)Objectのclone()はprotected.パッケージ内またはサブクラスでのみ呼び出すことができます.
3)上記のAddresのように、浅いクローン化されたオブジェクトにオブジェクト形式のメンバー変数がある場合.では
Employee e23=(Employee)e13.clone();//割り当てオブジェクト
e 13オブジェクトの基本タイプと不変量をコピーするだけである.可変のオブジェクトメンバー変数のコピーは依然として参照である.
以上のように印刷するシステム.out.println("e13.getAddr()==e23.getAddr():"+(e13.getAddr()==e23.getAddr()));//true.
変数には、a.Stringクラスオブジェクトb.がfinalによって定義され、サブオブジェクトは生存期間中に定数のみを保存する.
4)セグメントの場合
Employee e12=new Employee(" ",500,new Address("  ")); //Employee          
		 Employee e22=(Employee)e12.clone(); //       
		 e22.setName(" ");//    e2      
		 e22.setSalary(1000);
		 e22.setAddr(new Address("  "));
		 System.out.println("e12:"+e12); //  e1   : Employee [addr=Address [city=  ], name= , salary=500]
		 System.out.println("e22:"+e22); //  e1   : Employee [addr=Address [city=  ], name= , salary=1000]
		 System.out.println("e12.getAddr()==e22.getAddr():"+(e12.getAddr()==e22.getAddr()));//false
		 System.out.println(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>");

長い間やっていたが,浅いコピーではないか.どうしてe 12とe 22は同じ場所を指しているのですか.どうしたの?out.println("e12.getAddr()==e22.getAddr():"+(e12.getAddr()==e22.getAddr()));falseとして印刷します.
急にぼんやりさせられて、同級生に聞いてみた.コピーしたのはAdressがコピーリファレンスだったが、後でe 22のAddressリファレンスをe 22に変更した.setAddr(new Address(「上海」)(注意コピー完改の肯定e 12.getAddr()=e 22.getAddr()はfalseに着席しました).
3.深いコピー上のEmployeeクラスのcloneメソッドを変更します.
次のコードがあります.
	@Override
	protected Object clone() throws CloneNotSupportedException {
		Employee cloned=(Employee)super.clone();
		cloned.addr=(Address)addr.clone();
		return cloned;
	}

コード#コード#
public static void main(String[] args) throws CloneNotSupportedException{ //
		 Employee e13=new Employee(" ",500,new Address("  ")); //Employee          
		 Employee e23=(Employee)e13.clone(); //       
		 e23.setName(" ");//    e2      
		 e23.setSalary(1000);
		 e23.getAddr().setCity("  ");		 
		 System.out.println("e13:"+e13); //  e1   : Employee [addr=Address [city=  ], name= , salary=500]
		 System.out.println("e23:"+e23); //  e1   : Employee [addr=Address [city=  ], name= , salary=1000]
		 System.out.println("e13.getAddr()==e23.getAddr():"+(e13.getAddr()==e23.getAddr()));
	 }
の出力結果は(深いコピー):
e13:Employee [addr=Address [city=  ], name= , salary=500]
e23:Employee [addr=Address [city=  ], name= , salary=1000]
e13.getAddr()==e23.getAddr():false

方法(四)シーケンス化によるクローン化
次のコード
package com;


import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;


class Country implements Serializable{
	String coutry;
	Country (){
	}
}
class Address extends Country implements Serializable {
	String city;
	Address(String city,String country){
		this.city=city;
		this.coutry=country;
	}
	public String getCity() {
		return city;
	}


	@Override
	public String toString() {
		return "Address [city=" + city + ", coutry=" + coutry + "]";
	}
	public void setCity(String city) {
		this.city = city;
	}
	@Override
	protected Object clone() throws CloneNotSupportedException {
		return super.clone();
	}
}
class SerialCloneable implements Cloneable, Serializable
{  
   public Object clone()
   {  
      try
      {  
         // save the object to a byte array
         ByteArrayOutputStream bout = new 
            ByteArrayOutputStream();
         ObjectOutputStream out 
            = new ObjectOutputStream(bout);
         out.writeObject(this);
         System.out.println("bout.size:"+bout.size());//             ,                 。
         out.close();
         // read a clone of the object from the byte array
         ByteArrayInputStream bin = new 
            ByteArrayInputStream(bout.toByteArray());
         ObjectInputStream in = new ObjectInputStream(bin);
         Object ret = in.readObject();
         in.close();
         return ret;
      }  
      catch (Exception e)
      {  
         e.printStackTrace();
         return null;
      }
   }
}
public class Employee extends SerialCloneable{
	//public static int experience=10;
	String name;
	transient int salary;
	Address addr;


	public Employee(String name,int salary,Address city){
		this.name=name;
		this.salary=salary;
		this.addr=city;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public int getSalary() {
		return salary;
	}
	public void setSalary(int salary) {
		this.salary = salary;
	}
	public Address getAddr() {
		return addr;
	}
	public void setAddr(Address addr) {
		this.addr = addr;
	}
	@Override
	public String toString() {
		/*return "Employee [addr=" + addr + ", name=" + name + ", salary="
				+ salary +",experience="+this.experience+"]";*/
		return "Employee [addr=" + addr + ", name=" + name + ", salary="
		+ salary +"]";
	}
	@Override
	public Object clone() {
		return super.clone();
	}
	public static void main(String[] args) throws CloneNotSupportedException{ //
		 Employee e13=new Employee(" ",500,new Address("  ","  ")); //Employee          
		 Employee e23=(Employee)e13.clone(); //      
		 System.out.println("e13:"+e13); //  e1   : Employee Employee [addr=Address [city=  ], name= , salary=500]
		 System.out.println("e23:"+e23); //  e1   :  Employee Employee [addr=Address [city=  ], name= , salary=500]
		 System.out.println("e13.getAddr()==e23.getAddr():"+(e13.getAddr()==e23.getAddr()));
	 }
}

実行結果:
bout.size:222//  //public static int experience=10;             222   static         。
e13:Employee [addr=Address [city=  , coutry=  ], name= , salary=500]
e23:Employee [addr=Address [city=  , coutry=  ], name= , salary=0] salary =0   :transient         。
e13.getAddr()==e23.getAddr():false
1.注意開始時にAddressクラスが書かれています.
class Address{
......
}
結果:
java.io.NotSerializableException: com.Address異常.
最後にclass Address implements Serializableに変更すればいいです.したがって,シーケンス話を用いてcloneを行う場合,メンバオブジェクトに対応するクラスはいずれもSerializableインタフェースを実現すべきである.2.Countryがimplements Serializableを実装しない場合、上記のエラーは報告されませんが、シーケンス化されません.
class Country {
	String coutry;
	Country (){
	}
}
出力結果から、
bout.size:179
e13:Employee [addr=Address [city=  , coutry=  ], name=   , salary=500]
e23:Employee [addr=Address [city=  , coutry=null], name=   , salary=0]//country=null;        。        Serializable //         。
e13.getAddr()==e23.getAddr():false

方法(五)反射によるクローン化
1つのオブジェクトをコピーするには、シーケンス化とクローン化の2つの方法があります.シーケンス化を使用してレプリケーションを行うのは便利です.この方法では、シーケンス化するオブジェクトだけが自動的に深層レプリケーションされます.
対応するクラスは、オブジェクトで参照されている他のオブジェクトを一緒にコピーするシリアル化された表示インタフェースSerializableを実装しますが、この効率はObjectのcloneクローンメソッドには及ばない.ただし、
クローンをクローン化するのは浅いレプリケーションで、オブジェクトに参照されている他のオブジェクトは自動的に行われません.
深層クローンですので、深層コピーをしたい場合は、Objectのcloneメソッドを上書きし、深層コピーが必要なドメインを個別に処理する必要がありますので、適用するのが面倒です.
反射的に深層クローンcloneを行い、クローンされたクラスがこのクラスDeepCloneを継承するだけでよい.
ブログ参照http://www.iteye.com/topic/659877#1484197 .(上手に書いてあります)