How to clone objects?

  • Thread starter =?iso-8859-1?B?bW9vcJk=?=
  • Start date

?

=?iso-8859-1?B?bW9vcJk=?=

Hi,
In my scenerio, building up a class is a difficult task and cost a lot
of time. I want to store a copy of the object, which has no specific
detail value. When request the object, I can clone a copy of that and
use the copy would not affect the original one, so I can change
whatever value of the cloned one and get another pure clones from the
original. But I don't know how to use the clone() method suitablely,
anyone helps? Thx!
 
Ad

Advertisements

V

Viator

I am not commenting on the design that but for that you have to
implement Cloneable interface.

Amit :)
 
J

J. Verdrengh

In my experience, the way with the least potential problems is defining a
new instance method (like YourClass.duplicate() ) or a copy constructor
(like YourClass.YourClass(YourClass copyMe) ) in which you create a copy of
<this> / <copyMe>. This way you don't have to think about overriding clone()
and the consequences of doing that.

Jeroen
 
C

Chris Smith

moop? said:
In my scenerio, building up a class is a difficult task and cost a lot
of time. I want to store a copy of the object, which has no specific
detail value. When request the object, I can clone a copy of that and
use the copy would not affect the original one, so I can change
whatever value of the cloned one and get another pure clones from the
original. But I don't know how to use the clone() method suitablely,
anyone helps? Thx!

Cloning is a little complicated. The steps are as follows:

1. Implement the Cloneable interface.
2. Override the clone method from Object.
3. Have the clone method call the superclass.
4. Have the clone method recursively clone any nonmutable objects that
are components of this one.
5. Unless clone is actually likely to fail because of step 4, convert
CloneNotSupportedException to a RuntimeException.

It looks like this:

public class MyPrototype implements Cloneable
{
int value; // primitive type
String name; // reference to immutable object
Date lastUse; // reference to mutable object
UserAccount lastUser; // reference to non-component object

public Object clone()
{
try
{
MyPrototype other = (MyPrototype) super.clone();
other.lastUse = lastUser.clone();

return other;
}
catch (CloneNotSupportedException e)
{
throw new RuntimeException(e);
}
}
}

A few notes:

(a)

Note that of the four fields, only one had to be explicitly copied in
the clone() method. In fact, all fields will be copied automatically by
the call to super.clone(). The thing to remember is that when a field
is a reference to an object, the reference is copied, and NOT the
object. So all primitive types are safe.

If the reference points to an immutable object, that's also safe. The
object is not copied, so it will be shared between the original and the
clone. Since it's immutable, though, that is okay. No operations on
the object can cause it to act differently for the twin. If one of the
other object reassigns their reference to a different object, the twin
won't be affected.

The last two references (lastUse and lastUser, to Date and UserAccount)
are the more subtle distinction. The Date is actually PART of the
concept of this object, so it needs to be copied (since Date is mutable)
to prevent the last use date of this object from being changed when its
twin is used. The UserAccount, though, is NOT part of the meaning of
this object. It's just associated with this object. We don't need a
second UserAccount when cloning this object.

(b)

Why swallow the checked exception? Because if someone has a reference
to MyPrototype, they should be confident that it can be cloned. You
don't want to force them to handle at compile time the possibility that
you screwed up and forgot to implement Cloneable or called clone() on a
non-Cloneable field.

If you do NOT think they should be confident of this for some reason
(for example, because you're calling clone() on arbitrary Object
references that they passed in), then feel free to not swallow the
exception and document why it won't occur.

--
www.designacourse.com
The Easiest Way To Train Anyone... Anywhere.

Chris Smith - Lead Software Developer/Technical Trainer
MindIQ Corporation
 
C

Chris Smith

J. Verdrengh said:
In my experience, the way with the least potential problems is defining a
new instance method (like YourClass.duplicate() ) or a copy constructor
(like YourClass.YourClass(YourClass copyMe) ) in which you create a copy of
<this> / <copyMe>. This way you don't have to think about overriding clone()
and the consequences of doing that.

On the other hand, if you want a clone, why would you avoid clone()? If
this class may have subclasses, then the copy constructor won't work...
and if its constructors have side-effects, you can't reliably create a
clone WITHOUT calling Object.clone() at some point. These are the
problems that clone() was invented to solve.

--
www.designacourse.com
The Easiest Way To Train Anyone... Anywhere.

Chris Smith - Lead Software Developer/Technical Trainer
MindIQ Corporation
 
Ad

Advertisements

Z

zero

Cloning is a little complicated. The steps are as follows:

1. Implement the Cloneable interface.
2. Override the clone method from Object.
3. Have the clone method call the superclass.
4. Have the clone method recursively clone any nonmutable objects that
are components of this one.
5. Unless clone is actually likely to fail because of step 4, convert
CloneNotSupportedException to a RuntimeException.

It looks like this:

public class MyPrototype implements Cloneable
{
int value; // primitive type
String name; // reference to immutable object
Date lastUse; // reference to mutable object
UserAccount lastUser; // reference to non-component object

public Object clone()
{
try
{
MyPrototype other = (MyPrototype) super.clone();
other.lastUse = lastUser.clone();

you probably mean other.lastUse = lastUse.clone(); right?

<snip>

Seems like a good explanation. Ever think of putting it online? Or maybe
Roedy could put it on mindprod.
 
J

J. Verdrengh

On the other hand, if you want a clone, why would you avoid clone()?

One reason could be because the semantics of clone() are ambiguous: the same
method is used for deep copying in one class & shallow copying in another
class.
 
C

Chris Smith

The Conqueror said:
Create a copy constructor for it.Thats the easiest option for you.

Once again... if there's every a chance that this class will have
subclasses, a copy constructor is NOT a reasonable choice.

--
www.designacourse.com
The Easiest Way To Train Anyone... Anywhere.

Chris Smith - Lead Software Developer/Technical Trainer
MindIQ Corporation
 
Ad

Advertisements

R

Roedy Green

Once again... if there's every a chance that this class will have
subclasses, a copy constructor is NOT a reasonable choice.

Are you sure? I think the default clone implementation just copies
all bytes in the given object. That should produce a cloned subclass
as well. Has anyone done an experiment to see if clone gives you the
class where clone was defined or the subclass of the cloned object?
 
C

Chris Smith

Roedy Green said:
Are you sure? I think the default clone implementation just copies
all bytes in the given object. That should produce a cloned subclass
as well. Has anyone done an experiment to see if clone gives you the
class where clone was defined or the subclass of the cloned object?

You seem to have misunderstood.

Clone will do the right thing. That is, the class of the resulting
object is the same as the class of the object that's cloned. This is
different from a "copy constructor" (C++ terminology) which will produce
an object of some compile-time known class that may be a superclass of
the object. In other words, C++ style copy constructors exhibit a
truncation problem for subclasses, while clone solves that problem.

(Note that this is fine for the situation in which C++ copy constructors
are meant to be used... when passing or returning "auto" objectoids
whose class is necessarily known at compile-time anyway. C++ will never
apply a copy constructor implicitly when passing pointers to true
objects. It's just when you try to apply it to true objects that copy
constructors fail with subclasses.)

--
www.designacourse.com
The Easiest Way To Train Anyone... Anywhere.

Chris Smith - Lead Software Developer/Technical Trainer
MindIQ Corporation
 
A

Alex Molochnikov

Chris Smith said:
Yes. :) And I messed a necessary cast.

You also messed this part:
4. Have the clone method recursively clone any nonmutable objects that
are components of this one.

It took me by surprise until I reached the end of the post and realized that
"nonmutable" was a typo, meant to spell "mutable".

Alex Molochnikov
Gestalt Corporation
 
C

Chris Smith

Alex Molochnikov said:
You also messed this part:

are components of this one.

It took me by surprise until I reached the end of the post and realized that
"nonmutable" was a typo, meant to spell "mutable".

Yes, that's right.

--
www.designacourse.com
The Easiest Way To Train Anyone... Anywhere.

Chris Smith - Lead Software Developer/Technical Trainer
MindIQ Corporation
 
C

Chris Smith

zero said:
Seems like a good explanation. Ever think of putting it online? Or maybe
Roedy could put it on mindprod.

I would if JINX worked reliably. Roedy is welcome to it, though the
corrections should be applied.

--
www.designacourse.com
The Easiest Way To Train Anyone... Anywhere.

Chris Smith - Lead Software Developer/Technical Trainer
MindIQ Corporation
 
Ad

Advertisements

T

Thomas Weidenfeller

J. Verdrengh said:
One reason could be because the semantics of clone() are ambiguous: the same
method is used for deep copying in one class & shallow copying in another
class.

So what? If it is your own class, you implement whatever cloning
behavior you want in the clone() method.

/Thomas
 
Ad

Advertisements

D

Darryl L. Pierce

The said:
Create a copy constructor for it.Thats the easiest option for you.

Why, when Java gives you both the Object.clone() method and the
Cloneable interface? Copy constructors are a C++ paradigm.
 
Ad

Advertisements


Top