Jump to content
  • Advertisement
Sign in to follow this  
Fred304

[java] cloning objects correctly

This topic is 4652 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

As I just learned, cloning in Java can't be achieved by using a "copy constructor". You have to implement the Interface Cloneable instead and call super.clone() in your own clone() method for a shallow copy. After that, you must take whatever steps necessary to make a deep copy (if that is the desired behavior). As I've never done this before I post the clone() methods of two of my classes and would ask you to check if I got this right: shallow copy of two int values:
public class Slice implements Cloneable
{
	private int _bot;
	private int _top;

	[...]

	public Object clone()
	{
		Slice that = null;
		try
		{
			that = (Slice) super.clone();
		}
		catch (CloneNotSupportedException e)
		{
			e.printStackTrace();
			System.exit(-1);
		}
		return that;
	}
}

array has to be copied to get a deep copy, rest is shallow:
public class Piece implements Cloneable
{
	private Slice[] _slice;
	private int _capacity;
	private int _left;
	private int _right;

	[...]

	public Object clone()  
	{
		assert isReduced() : "Vorbedingung verletzt: isReduced()";
		Piece that = null;
		try
		{
			that = (Piece) super.clone();
		}
		catch (CloneNotSupportedException e)
		{
			e.printStackTrace();
			System.exit(-1);
		}
		
		that._slice = new Slice[_capacity];
		
		for (int i=_left; i<_right; i++)
		{
			that._slice = (Slice) _slice.clone();
		}

		assert that.isReduced() : "Nachbedingung verletzt: result.isReduced()";
		return that;
	}
}

Is there any way to get rid of these nasty typecasts? I thought I would have gotten rid of them at last with the introduction of generics.

Share this post


Link to post
Share on other sites
Advertisement
You call super.clone() to make it a deep copy. But you also have to copy your own data.


public class Slice implements Cloneable
{
private int _bot;
private int _top;

[...]

public Object clone()
{
Slice that = null;
try
{
that = (Slice) super.clone();
that._bot =_bot;
that._top =_top;
}
catch (CloneNotSupportedException e)
{
e.printStackTrace();
System.exit(-1);
}
return that;
}
}



public class Piece implements Cloneable
{
private Slice[] _slice;
private int _capacity;
private int _left;
private int _right;

[...]

public Object clone()
{
assert isReduced() : "Vorbedingung verletzt: isReduced()";
Piece that = null;
try
{
that = (Piece) super.clone();
that._capacity = _capacity;
that._left= _left;
that._right= _right;
}
catch (CloneNotSupportedException e)
{
e.printStackTrace();
System.exit(-1);
}

that._slice = new Slice[_capacity];

for (int i=_left; i<_right; i++)
{
that._slice = (Slice) _slice.clone();
}

assert that.isReduced() : "Nachbedingung verletzt: result.isReduced()";
return that;
}
}

Share this post


Link to post
Share on other sites
Quote:
Original post by CaptainJester
You call super.clone() to make it a deep copy. But you also have to copy your own data.

I did a little more research - and these statements are definately wrong!

Quote:
http://java.sun.com/j2se/1.5.0/docs/api/java/lang/Object.html#clone()
If a class contains only primitive fields or references to immutable objects, then it is usually the case that no fields in the object returned by super.clone need to be modified.

The method clone for class Object performs a specific cloning operation. First, if the class of this object does not implement the interface Cloneable, then a CloneNotSupportedException is thrown. Note that all arrays are considered to implement the interface Cloneable. Otherwise, this method creates a new instance of the class of this object and initializes all its fields with exactly the contents of the corresponding fields of this object, as if by assignment; the contents of the fields are not themselves cloned. Thus, this method performs a "shallow copy" of this object, not a "deep copy" operation.

Share this post


Link to post
Share on other sites
Quote:
Original post by Fred304
Quote:
Original post by CaptainJester
You call super.clone() to make it a deep copy. But you also have to copy your own data.

I did a little more research - and these statements are definately wrong!

Quote:
http://java.sun.com/j2se/1.5.0/docs/api/java/lang/Object.html#clone()
If a class contains only primitive fields or references to immutable objects, then it is usually the case that no fields in the object returned by super.clone need to be modified.

The method clone for class Object performs a specific cloning operation. First, if the class of this object does not implement the interface Cloneable, then a CloneNotSupportedException is thrown. Note that all arrays are considered to implement the interface Cloneable. Otherwise, this method creates a new instance of the class of this object and initializes all its fields with exactly the contents of the corresponding fields of this object, as if by assignment; the contents of the fields are not themselves cloned. Thus, this method performs a "shallow copy" of this object, not a "deep copy" operation.


what this means is that a clone of this class;
class Something implements Cloneable{
public int primitiveI;
public Integer classI;
//implement the clone interface
}

will create two classes, each with a copy of primitiveI with equivalent, and each with a copy of classI with equivalent values. It is at this point important to note that object references are more analogous to C++ pointers. classI is storing a memory address. So, that memory address is being copied and stored in the clone's classI member, but it points to the same instance of the Integer class that the original instance's classI member points to.

so, using the code from above

Something a = new Something();
a.primitiveInt = 3;
a.classInt = new Integer(7);

Something b = a.clone();

a.primitiveInt = 4;
a.classInt.setValue(10); //if we could do such a thing, as opposed to creating a new Integer instance


a.primitiveInt is now 4, b.primitiveInt is still 3.
a.classInt and b.classInt are both 10.

Share this post


Link to post
Share on other sites
Quote:
Original post by capn_midnight
Quote:
Original post by Fred304
Quote:
Original post by CaptainJester
You call super.clone() to make it a deep copy. But you also have to copy your own data.

I did a little more research - and these statements are definately wrong!


Maybe my post was ambiguous, I meant CaptainJester's statements are wrong.

Quote:

what this means is that a clone of this class [...] will create two classes

You don't clone the class, you clone the instance and get another instance.

Quote:

a.classInt.setValue(10); // if we could do such a thing

And since we can't it's not a problem that both instances refer to the same object: "If a class contains only primitive fields or references to immutable objects, then it is usually the case that no fields in the object returned by super.clone need to be modified."

Share this post


Link to post
Share on other sites
Original post by Fred304
Quote:
Original post by capn_midnight
Quote:

what this means is that a clone of this class [...] will create two classes

You don't clone the class, you clone the instance and get another instance.

typo
Quote:

Quote:

a.classInt.setValue(10); // if we could do such a thing

And since we can't it's not a problem that both instances refer to the same object: "If a class contains only primitive fields or references to immutable objects, then it is usually the case that no fields in the object returned by super.clone need to be modified."
but it is a problem for other classes that do allow you to edit their contents. I used Integer becuase it's familar, and it compares to the primitive type int. I used this example to explain *why* cloning doesn't always work, because you are copying memory addresses, not the actual instances.

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

Participate in the game development conversation and more when you create an account on GameDev.net!

Sign me up!