On Java shallow cloning and deep cloning

Source: Internet
Author: User
Tags stub

If we have an object A and we want a clone of it, then what do we do? The most intuitive, the most stupid way is we first new a of the same object B, and then copy A's property to the corresponding property in B. So, there are two concepts that need to come out right now: shallow cloning and deep cloning.

If the two concepts are interpreted in a straightforward, not strictly defined language, then it can be said that:

A shallow clone is a copy of an instance of an object, but the other objects contained in this object are still shared.

Deep cloning refers to the copying of an instance of an object, and the other objects contained in the object are copied.

If we want to clone an object deeply, and this object is more complex, it also contains n many other objects of the reference, then we start to say that the cloning method, it is a human life! Even if we only have a shallow cloned object, if the object has dozens of hundred basic attributes, it is unacceptable for us to copy each one.

So, let's take a look at how a shallow clone of an object in Java can be done.

The Object class provides a clone method whose method signature is as follows:

Protected native Object clone () throws Clonenotsupportedexception;

Can see: (1) It is a native method. Generally speaking, the efficiency of native method is much higher than that of native method.

(2) It is a protected method.

(3) It returns an object.

If we were to invoke the Clone method in another class, we would override this method and change its method property to public. This method actually provides the function of shallow cloning.

The code for the validation is as follows:

Swallow.java:

Package com.myclone.test;


public class Swallow implements cloneable{


	private String name;
	Private Wing leftwing;
	Private Wing rightwing;
	
	Public Swallow (String name, Wing leftwing, Wing rightwing) {
		this.name = name;
		this.leftwing = leftwing;
		this.rightwing = rightwing;
	}

	Public String GetName () {return
		name;
	}

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

	Public Wing getleftwing () {return
		leftwing;
	}

	public void setleftwing (Wing leftwing) {
		this.leftwing = leftwing;
	}

	Public Wing getrightwing () {return
		rightwing;
	}

	public void setrightwing (Wing rightwing) {
		this.rightwing = rightwing;
	}
	
	@Override
	protected Object Clone () throws Clonenotsupportedexception {
		//TODO automatically generated method stub return
		Super.clone ();
	}


Wing.java:

Package com.myclone.test;

public class wing{

	private int width;

	public Wing (int width) {
		this.width = width;
	}
	
	public int getwidth () {return
		width;
	}

	public void setwidth (int width) {
		this.width = width;
	}
}

Main.java:

Package com.myclone.test;

public class Main {public

static void Main (string[] args) throws Clonenotsupportedexception {
//TODO        Automatically generated method stub

Swallow s1 = new Swallow ("Wild Goose A", New Wing (a), New Wing ());
Swallow s2 = (swallow) s1.clone ();
System.out.println ("(s1==s2) =" + (S1==S2));
System.out.println ("s1.name=" + s1.getname () + ", s2.name=" +s2.getname ());
System.out.println ("(s1.leftwing==s2.leftwing) =" + (s1.getleftwing () ==s2.getleftwing ());
System.out.println ("(s1.rightwing==s2.rightwing) =" + (s1.getrightwing () ==s2.getrightwing ());
}
}


Run Result:

(S1==S2) =false
S1.name= Wild Goose A, s2.name= wild goose A
(s1.leftwing==s2.leftwing) = True
(s1.rightwing==s2.rightwing) = True

We can see from the results of the operation that the call to the S1.clone () method We get is another object, it is a shallow clone of S1, because the S1 and S2 object Properties leftwing point to the same instance, rightwing point to the same instance. Note: To invoke the Clone method, you must implement the Cloneable interface, which in our case is the swallow implementation of the Cloneable interface.


What if we need a deeply cloned object. The first thing we think about is that you can rewrite the Clone method in swallow to clone a copy of leftwing and rightwing. So wing also rewrite its clone method and rewrite the wing class:

Package com.myclone.test;

public class Wing implements cloneable{

	private int width;

	public Wing (int width) {
		this.width = width;
	}
	
	public int getwidth () {return
		width;
	}

	public void setwidth (int width) {
		this.width = width;
	}
	
	@Override
	protected Object Clone () throws Clonenotsupportedexception {
		//TODO automatically generated method stub return
		Super.clone ();
	}


Rewritten Swallow class:

Package com.myclone.test;
	public class Swallow implements cloneable{private String name;
	Private Wing leftwing;
	
	Private Wing rightwing;
		Public Swallow (String name, Wing leftwing, Wing rightwing) {this.name = name;
		this.leftwing = leftwing;
	this.rightwing = rightwing;
	Public String GetName () {return name;
	public void SetName (String name) {this.name = name;
	Public Wing getleftwing () {return leftwing;
	public void setleftwing (Wing leftwing) {this.leftwing = leftwing;
	Public Wing getrightwing () {return rightwing;
	public void setrightwing (Wing rightwing) {this.rightwing = rightwing; }//@Override//Protected Object Clone () throws Clonenotsupportedexception {////TODO automatically generated method stub//return super.cl
One (); @Override protected Object Clone () throws Clonenotsupportedexception {//TODO automatically generated method stubs swallow swallow = (S
		Wallow) Super.clone ();
		Wing lefwing = (Wing) swallow.getleftwing (). Clone (); Wing rightwing = (Wing) swallow.getrightwing (). Clone ();
		Swallow.setleftwing (lefwing);
		Swallow.setrightwing (rightwing);
	return swallow;
 }
}

Run main again, and the result is:

(S1==S2) =false
S1.name= Wild Goose A, s2.name= wild goose A
(s1.leftwing==s2.leftwing) = False
(s1.rightwing==s2.rightwing) = False

It can be seen that S2 is already a deep clone of S1. One drawback of this approach is that if wing also contains object attributes, then we have to override the attribute class's Clone method in turn.

Another approach is to implement deep cloning by serializing and deserializing. This approach is actually "to make the object implement the serializable interface, then write the object (actually just a copy of the object) into a stream, and then read out of the stream, you can reconstruct the object." "--java.lang.object.clone () analysis

Note that all related classes implement the Serializable interface, overwriting the instance:

Wing.java

Package com.myclone.test;

Import java.io.Serializable;

public class Wing implements Cloneable, serializable{

	/**
	 * */
	private static final long Serialversionuid = -6757262538695878009l;
	private int width;

	public Wing (int width) {
		this.width = width;
	}
	
	public int getwidth () {return
		width;
	}

	public void setwidth (int width) {
		this.width = width;
	}
	
	@Override
	protected Object Clone () throws Clonenotsupportedexception {
		//TODO automatically generated method stub return
		Super.clone ();
	}


Swallow.java

Package com.myclone.test;
Import Java.io.ByteArrayInputStream;
Import Java.io.ByteArrayOutputStream;
Import java.io.IOException;
Import Java.io.ObjectInputStream;
Import Java.io.ObjectOutputStream;


Import java.io.Serializable; public class Swallow implements Cloneable, serializable{/** * */private static final long Serialversionuid =-2
	152309743441152834L;
	private String name;
	Private Wing leftwing;
	
	Private Wing rightwing;
		Public Swallow (String name, Wing leftwing, Wing rightwing) {this.name = name;
		this.leftwing = leftwing;
	this.rightwing = rightwing;
	Public String GetName () {return name;
	public void SetName (String name) {this.name = name;
	Public Wing getleftwing () {return leftwing;
	public void setleftwing (Wing leftwing) {this.leftwing = leftwing;
	Public Wing getrightwing () {return rightwing;
	public void setrightwing (Wing rightwing) {this.rightwing = rightwing; }//@Override//Protected Object clone () throws clonenotsupportedexception {////TODO automatically generated method stub//return Super.clone ();//} @Override protected Object clone ()
		Throws Clonenotsupportedexception {//TODO automatically generated method stub swallow swallow = (swallow) super.clone ();
		Wing lefwing = (Wing) swallow.getleftwing (). Clone ();
		Wing rightwing = (Wing) swallow.getrightwing (). Clone ();
		Swallow.setleftwing (lefwing);
		Swallow.setrightwing (rightwing);
	return swallow; /** * Deep Clone * @return * @throws IOException * @throws classnotfoundexception/public Object deepclone () th
		Rows IOException, classnotfoundexception{bytearrayoutputstream BAOs = new Bytearrayoutputstream ();
		ObjectOutputStream oos = new ObjectOutputStream (BAOs);
		
		Oos.writeobject (this);
		Bytearrayinputstream Bais = new Bytearrayinputstream (Baos.tobytearray ());
		ObjectInputStream ois = new ObjectInputStream (Bais);
	return Ois.readobject ();
 }
}

Main.java:

Package com.myclone.test;

Import java.io.IOException;

public class Main {public

	static void Main (string[] args) throws Clonenotsupportedexception, ClassNotFoundException , IOException {
		//TODO automatically generated method stubs

		swallow s1 = new Swallow ("Wild Goose A", New Wing (a), New Wing ());
		Swallow s2 = (swallow) s1.clone ();
		Swallow s2 = (swallow) s1.deepclone ();
		
		System.out.println ("(s1==s2) =" + (S1==S2));
		System.out.println ("s1.name=" + s1.getname () + ", s2.name=" +s2.getname ());
		System.out.println ("(s1.leftwing==s2.leftwing) =" + (s1.getleftwing () ==s2.getleftwing ());
		System.out.println ("(s1.rightwing==s2.rightwing) =" + (s1.getrightwing () ==s2.getrightwing ());	 
	}


Run Result:

(S1==S2) =false
S1.name= Wild Goose A, s2.name= wild goose A
(s1.leftwing==s2.leftwing) = False
(s1.rightwing==s2.rightwing) = False


Thus, it is most elegant and convenient to realize deep cloning by serialization and deserialization.

2015.09.02 Supplements:

One of my colleagues said in the morning that there is another way to do this, that is, using JSON, which is really a good way. So, we can add a DeepClone2 method to the Swallow class, and the effect is the same:

Public Swallow DeepClone2 () {
        Gson Gson = new Gson ();
        String JSON = Gson.tojson (this);
        Return Gson.fromjson (JSON, This.getclass ());
    }
It seems to be simpler ~ but I was wondering if it would be less efficient and tested the next 100,000 clones, and the results were as follows:

Deepclone method is time-consuming =1564
DeepClone2 method is time-consuming =4029



Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.