super.clone() puzzlement

D

Derek Fountain

As a newbie, I was just looking at using super.clone(). My class doesn't
extend anything directly, so it's basically an Object with a few fields
of its own. My clone() method does this:

Object clone = super.clone();

but when I single step that line in Eclipse I see the new object, clone,
has the instance fields of my class.

My understanding was that my use of super.clone() will actually call
Object.clone() to create the new object. Assuming that's right, is
Object.clone() smart enough to see my class's instance fields and copy
them or is there some other magic going on elsewhere in the clone
process that I don't understand?
 
G

GArlington

As a newbie, I was just looking at using super.clone(). My class doesn't
extend anything directly, so it's basically an Object with a few fields
of its own. My clone() method does this:

   Object clone = super.clone();

but when I single step that line in Eclipse I see the new object, clone,
has the instance fields of my class.

My understanding was that my use of super.clone() will actually call
Object.clone() to create the new object. Assuming that's right, is
Object.clone() smart enough to see my class's instance fields and copy
them or is there some other magic going on elsewhere in the clone
process that I don't understand?

Are you trying to say that your clone() does NOT throw
CloneNotSupportedException?
 
M

Mark Space

Derek said:
My understanding was that my use of super.clone() will actually call
Object.clone() to create the new object. Assuming that's right, is
Object.clone() smart enough to see my class's instance fields and copy
them or is there some other magic going on elsewhere in the clone
process that I don't understand?

Yup, basically, Object can see the real type of your class and can make
all the instance fields. Try calling "getClass().getName()" in a base
class, then invoke that from a child class. It'll return the name of
the child class. Polymorphism for the win.

Clone is a weird beast. Joshua Bloch goes into a lot of detail when,
and more importantly when not, to use .clone() in his _Effective Java_.
Calling super.clone() is the only way to get a proper object when your
class is non-final. And if your class is non-final, you have to
remember that what you get back might not be your class but a child
class that somebody has extended. Then there's issues with copying
instance fields so they don't share state. And final fields often won't
work. It's a bucket o' fun to do correctly.

Basically, clone is ok sometimes, but also consider a copy constructor.
Generally, a copy constructor is more useful and less prone to mistakes.

public class MyClass {
public MyClass( MyClass mine ) {
//... make new class from old one...
}
}
 
D

Derek Fountain

Clone is a weird beast.

Yes, that much I've worked out. :) Shortly after posting I reread and
finally understood the Object.clone() documentation properly. There's
some cleverness in there, I assume reflection based, that allows it to
see what it's cloning and the fields it needs to duplicate.

I also started to understand why the Object.clone() method is protected.
I was working on the basis that Objects of all sorts are intrinsically
cloneable, and that being cloneable is a good and conventional thing.
But that's wrong: Objects are not cloneable unless subclassed and a
public clone() method is specifically added. This effectively "opens the
door" to the built in cloning mechanism which needs to be augmented as
appropriate. Now that I understand things better I can see why this
"door" defaults to closed - cloning of the class I'm working with is
something of a can of worms, and I need to think things through again in
order to achieve what I want.

Thanks for your input, it's appreciated. :)
 
D

Derek Fountain

Generally, a copy constructor is more useful and less prone to mistakes.
public class MyClass {
public MyClass( MyClass mine ) {
//... make new class from old one...
}
}

I have a class like this:

class MyClass {
Object value;

// Implementation...
}

I want a copy of the MyClass instance where value references a deep copy
of the value Object. That is, I want a copy of the MyClass instance
where, when I change the object referenced by its value, a copy I've
made of the MyClass instance keeps its own value object intact.

Am I right in thinking that given that I don't know what sort of Object
value actually is, I've no way of reliably making a copy of it? Either
with clone or a copy constructor or any other technique?

I guess I could change it to this:

class MyClass {
Cloneable value;
}

which would at least ensure the value was cloneable. But since I don't
want to restrict what the user can store in value, I'm going to have to
forego giving them a copy facility aren't I?
 
M

Mark Space

Derek said:
which would at least ensure the value was cloneable. But since I don't
want to restrict what the user can store in value, I'm going to have to
forego giving them a copy facility aren't I?

As far as I know, this is correct. Since most objects in the Java API
don't implement Cloneable, you have no reliable way of making a "deep
copy." You must force all objects to implement clone() with deep copy
semantics (not guaranteed by the clone() method itself) or you have no
way of arbitrarily copying an object.
 
T

Tom Anderson

I have a class like this:

class MyClass {
Object value;

// Implementation...
}

I want a copy of the MyClass instance where value references a deep copy of
the value Object. That is, I want a copy of the MyClass instance where, when
I change the object referenced by its value, a copy I've made of the MyClass
instance keeps its own value object intact.

Am I right in thinking that given that I don't know what sort of Object value
actually is, I've no way of reliably making a copy of it? Either with clone
or a copy constructor or any other technique?

I guess I could change it to this:

class MyClass {
Cloneable value;
}

which would at least ensure the value was cloneable. But since I don't want
to restrict what the user can store in value, I'm going to have to forego
giving them a copy facility aren't I?

Probably.

Do the values have to be arbitrary objects, so could be a string, date,
list, etc?

You might be able to do it if you define a sort of ValueCopier interface,
and then find a convenient way to plug it in. Something like:

interface ValueCopier<T> {
public T copy(T obj) ;
}

class MyClass<T> {
private T value ;
private ValueCopier<T> copier ;
public MyClass(T value, ValueCopier<T> copier) {
this.value = value ;
this.copier = copier ;
}
public MyClass (MyClass<T> other) {
this.value = other.copier.copy(other.value) ;
this.copier = other.copier ;
}
}

You'd have to write a copier for each kind of thing you wanted to use as a
value.

You might be able to use a static, global registry of copiers, organised
as a map by class, to avoid having to fiddle around with copiers on a
per-instance basis. That's a bit of a smelly solution, though.

tom
 
B

Bent C Dalager

Basically, clone is ok sometimes, but also consider a copy constructor.
Generally, a copy constructor is more useful and less prone to mistakes.

How is a copy constructor better? Unless you've created the object
yourself or it's of a final class then you can't really know which
copy constructor to call except through reflection.

Cheers,
Bent D
 
M

Mike Schilling

Eric said:
You're right, I think. Consider this use case:

MyClass m1 = new MyClass();
m1.setValue( SingletonClass.INSTANCE );
MyClass m2 = m1.clone(); // singleton becomes doubleton?

Is there a reason that clone() can't return "this"? That's more or less
equivalent to the standard behavior of having readResolve() return the
singleton instance.
 
B

Bent C Dalager

Is there a reason that clone() can't return "this"?

The contract for clone() says that

"By convention, the object returned by this method should be
independent of this object (which is being cloned)."

which implies that o.clone() cannot return o since an object is
clearly not independent of itself. This is probably not what is
intended however since the doc also explicitly says that
"o != o.clone()" is not an absolute requirement. Rather, it is
probably meant to say that "o.clone() cannot return an object
different from o that depends in some way on o".

In conclusion, returning "this" from clone() is probably permissible
but certainly not mainstream.

Cheers,
Bent.
 
A

Arne Vajhøj

Bent said:
The contract for clone() says that

"By convention, the object returned by this method should be
independent of this object (which is being cloned)."

which implies that o.clone() cannot return o since an object is
clearly not independent of itself. This is probably not what is
intended however since the doc also explicitly says that
"o != o.clone()" is not an absolute requirement. Rather, it is
probably meant to say that "o.clone() cannot return an object
different from o that depends in some way on o".

In conclusion, returning "this" from clone() is probably permissible
but certainly not mainstream.

Usually clone is used to create a copy that is to be modified
and still keep the original intact.

Arne
 
B

Bent C Dalager

Usually clone is used to create a copy that is to be modified
and still keep the original intact.

This is probably common enough. The lesson to draw about clone() from
all this, however, is that one cannot call clone() blindly on random
objects without knowing that particular class' contract for its
clone() method. Some may produce entirely new objects, some may not.
Some may have other important considerations.

Then again, this lesson is already enforced to a large extent by the
Java API since Cloneable doesn't declare clone() and Object declares
it as protected. It follows that when calling clone() on an object it
must already be of a specific type known to the programmer with a
public clone() and, one must hope, a clear contract for how this
method may be used (and how subclasses must implement it).

Cheers,
Bent D
 
A

Arne Vajhøj

Bent said:
This is probably common enough. The lesson to draw about clone() from
all this, however, is that one cannot call clone() blindly on random
objects without knowing that particular class' contract for its
clone() method. Some may produce entirely new objects, some may not.
Some may have other important considerations.

Then again, this lesson is already enforced to a large extent by the
Java API since Cloneable doesn't declare clone() and Object declares
it as protected. It follows that when calling clone() on an object it
must already be of a specific type known to the programmer with a
public clone() and, one must hope, a clear contract for how this
method may be used (and how subclasses must implement it).

Based on the wording:

"Typically, this means copying any mutable objects that comprise the
internal "deep structure" of the object being cloned and replacing the
references to these objects with references to the copies. 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."

and what is common practice, then I will expect a clone
to contain a copy, but only of first level - also
known as shallow clone.

If not then the docs better contain a warning in 72 point, red,
bold, blinking.

Arne
 
B

Bent C Dalager

Based on the wording:

"Typically, this means copying any mutable objects that comprise the
internal "deep structure" of the object being cloned and replacing the
references to these objects with references to the copies. 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."

and what is common practice, then I will expect a clone
to contain a copy, but only of first level - also
known as shallow clone.

If not then the docs better contain a warning in 72 point, red,
bold, blinking.

What the doc for Object.clone() basically says is that you have pretty
much no guarantee whatsoever what clone() is actually going to do. It
also says that it is ok, and even expected occasionally, that some
implementations break with what may be considered common practice (aka
"convention" in the actual doc). This being the case, it is advisable
to treat /all/ implementations of clone() as if they had a warning in
72 point red bold blinking letters saying "caveat emptor". Blindly
using a class' clone() implementation in the hope that it behaves as
you think it should is a recipe for disaster.

As a case in point, while you say that you would expect only a shallow
copy, the Object.clone() doc you quote above specifies that in the
case of contained mutable objects it is necessary that deep copies be
made in the conventional case. But, again, this is only presented as a
guideline.

Cheers,
Bent D
 
A

Arne Vajhøj

Bent said:
What the doc for Object.clone() basically says is that you have pretty
much no guarantee whatsoever what clone() is actually going to do. It
also says that it is ok, and even expected occasionally, that some
implementations break with what may be considered common practice (aka
"convention" in the actual doc). This being the case, it is advisable
to treat /all/ implementations of clone() as if they had a warning in
72 point red bold blinking letters saying "caveat emptor". Blindly
using a class' clone() implementation in the hope that it behaves as
you think it should is a recipe for disaster.

Java is not C.

I will expect code to follow convention or document its deviation.
As a case in point, while you say that you would expect only a shallow
copy, the Object.clone() doc you quote above specifies that in the
case of contained mutable objects it is necessary that deep copies be
made in the conventional case. But, again, this is only presented as a
guideline.

No. It talks about deep structures. It does not talk about
deep clone.

If you happen to have Joshua Bloch Effective Java 1st edition, then
item 10 covers the clone method in detail.

<quote>
The resulting mechanism is extralinguistic: It creates an
object without calling a constructor.
</quote>

And he gives two examples that show it is only the first
level fields that get cloned - not what they contain.

I assume he knows what was the intention with the
construct.

But he did probably not invent it, because he also has
some pretty harsh words about both the Cloneable interface
and about the text in the docs for the clone method.

Arne
 
B

Bent C Dalager

Java is not C.

This is trivially true of course. Why is it relevant?
I will expect code to follow convention or document its deviation.

This is a different strategy than the one you previously suggested of
just assuming that clone() followed convention. The main point about
clone() is /exactly/ to be highly observant of the documentation of
the class you are calling clone() on because it is permitted to do
pretty much anything.
No. It talks about deep structures. It does not talk about
deep clone.

How would you "[copy] any mutable objects that comprise the internal
'deep structure' of the object being cloned and [replace] the
references to these objects with references to the copies" except by
doing something deeper than just a shallow copy?
If you happen to have Joshua Bloch Effective Java 1st edition, then
item 10 covers the clone method in detail.

<quote>
The resulting mechanism is extralinguistic: It creates an
object without calling a constructor.
</quote>

And he gives two examples that show it is only the first
level fields that get cloned - not what they contain.

I assume he knows what was the intention with the
construct.

For primary source purposes, I would rather be using the actual
documentation from the people that designed the thing in the first
place. Bloch may have excellent advice for how people ought to
implement clone() but when you use the clone() that was implemented by
others you need to take into account the /actual/ contract they were
writing it under, not a theoretical model of how one might ideally be
going about it.

And, indeed, the clone() contract specifically states that you are
free to implement something other than a shallow copy - a shallow copy
is just the default algorithm implemented by Object. It then goes on
to state that in a specific set of circumstances you are not only
/allowed/ to do a deep clone but even /expected/ to do to.
But he did probably not invent it, because he also has
some pretty harsh words about both the Cloneable interface
and about the text in the docs for the clone method.

Of course he does - clone() is incredibly confusing and difficult to
use, which is exactly my point.

The correct approach to this is /not/ to wilfully ignore its
complexities and just hope against hope that everyone in the world
follows best practices but instead to be aware of the pitfalls and
take great care when using that method.

Cheers,
Bent D
 
M

Mark Space

Bent said:
How is a copy constructor better? Unless you've created the object
yourself or it's of a final class then you can't really know which
copy constructor to call except through reflection.

In this case you are correct -- constructors in Java are not
polymorphic, so if you need that behavior, you'd have to implement it in
some clumsy fashion using reflection.

Where I think copy constructors are better:

1. Semantics better defined that clone().

2. Able to use final fields which hold objects with internal state. (In
other words, if you need to do a deep copy with clone, you can't use a
final field for that variable. With a copy constructor, you can use a
final field just fine.)

3. Easier for programmers to understand and get right.

This doesn't mean copy constructors are always better, but you should
consider them. If your design can make do with just copy-ctors and
forgo clone(), then you probably should.
 
J

J. Davidson

Mark said:
Where I think copy constructors are better:

1. Semantics better defined that clone().

2. Able to use final fields which hold objects with internal state. (In
other words, if you need to do a deep copy with clone, you can't use a
final field for that variable. With a copy constructor, you can use a
final field just fine.)

3. Easier for programmers to understand and get right.

This doesn't mean copy constructors are always better, but you should
consider them. If your design can make do with just copy-ctors and
forgo clone(), then you probably should.

Why not have your cake and eat it too?

private (or whatever) Foo (Foo toCopy) {
this.fieldX = toCopy.fieldX;
this.fieldY = toCopy.fieldY;
this.fieldZ = toCopy.fieldZ.clone();
this.fieldW = new Bar(toCopy.fieldW);
}

public Foo clone () {
return new Foo(this);
}

Doesn't work to properly copy Foo subclasses though.

But maybe this does:

public interface Copier<T> {
T getCopy (T object);
}

public abstract class Foo<T extends Foo<T>> {
private Copier<T> copier;

protected Foo (Copier<T> copier) {
this.copier = copier;
}

@SuppressWarnings("unchecked");
public T clone () {
return copier.getCopy((T)this);
}
}

public class Bar extends Foo<Bar> {
private int field;

public Bar (int x) {
super(new Copier<Bar> () {
public Bar copy (Bar object) {
return new Bar(object.field);
}
});
field = x;
}

public int getX () {
return field;
}
}

One "curiously recurring template pattern", one
@SuppressWarnings("unchecked"), and one subclass that can copy itself.

Of course, this may still run into problems if you make subclasses of
subclasses. At least the type parameters can get hairy. Even then you
could just dump the generics and leave clone to return Object and
callers to cast.

public abstract class Baz <T extends Baz> extends Foo<T>, perhaps?

I seem to remember this kind of thing eventually confusing the compiler.
The 1.5 compiler anyway. Maybe 1.6 is better able to deal with this sort
of thing.

Oh, and as for someone else's suggestion of a ValueCopier, you could
make a generic ValueCopier for everything Serializable. Simplest is to
use File.createTemporaryFile, ObjectOutputStream, and ObjectInputStream.
Disk I/O is avoided by using ByteArrayOutputStream wrapped with
ObjectOutputStream, along with ByteArrayInputStream. It might also be
possible to use nio channels to create a sort of pipe. The lack of
multiple inheritance in Java makes it tricky but you can make a class
that contains an ArrayList<Byte> and has getInputStream and
getOutputStream methods that furnish inner class instances, one which
appends to the ArrayList at one end, and the other that consumes from
the other end and blocks if need be. You'd need to fiddle around with
synchronized, wait, and notify, and might want to use ArrayDeque instead
of ArrayList. The advantage over ByteArray streams is in memory use if
copying a very large object, assuming your ValueCopier<Serializable>
spawned a parallel thread to writeObject while the main thread did the
readObject and you got all your synchronization ducks in a row on your
DequeStream, or whatever you called it.

Now look what I've done. I've found a use in Java for the "curiously
recurring template pattern", which someone just said didn't work in
Java; I've found a real use for concurrency on single-core machines for
a task that doesn't involve network or disk I/O; and I've gone and
solved some other problems.

I thought I might even have found a need for
@SuppressWarnings("unchecked") that doesn't involve interfacing to
nongeneric legacy code, but I guess I haven't really, since clone isn't
generic and Object isn't generic. (Imagine if they'd had Object
parametrized by the run-time class of the actual object, like Foo is
above; Java might have been very different and not just in the clone
method.)

- jenny
 
T

Tom Anderson

Oh, and as for someone else's suggestion of a ValueCopier, you could
make a generic ValueCopier for everything Serializable.

Yes, or to use the mechanisms used for serialization (reflectively
examining, creating and modifying objects) to do the clone directly. The
JBoss guys have implemented their own serialization system which they also
use to do 'smart cloning':

http://www.jboss.org/serialization/

If you wanted to roll something like this by hand, you could do pretty
well with reflection, or use sun.misc.Unsafe for a more complete but hairy
solution.
Simplest is to use File.createTemporaryFile, ObjectOutputStream, and
ObjectInputStream. Disk I/O is avoided by using ByteArrayOutputStream
wrapped with ObjectOutputStream, along with ByteArrayInputStream. It
might also be possible to use nio channels to create a sort of pipe. The
lack of multiple inheritance in Java makes it tricky but you can make a
class that contains an ArrayList<Byte> and has getInputStream and
getOutputStream methods that furnish inner class instances, one which
appends to the ArrayList at one end, and the other that consumes from
the other end and blocks if need be. You'd need to fiddle around with
synchronized, wait, and notify, and might want to use ArrayDeque instead
of ArrayList. The advantage over ByteArray streams is in memory use if
copying a very large object, assuming your ValueCopier<Serializable>
spawned a parallel thread to writeObject while the main thread did the
readObject and you got all your synchronization ducks in a row on your
DequeStream, or whatever you called it.

I think you're looking for these:

http://java.sun.com/javase/6/docs/api/java/io/PipedInputStream.html
http://java.sun.com/javase/6/docs/api/java/io/PipedOutputStream.html

tom
 
M

Mark Space

J. Davidson said:
public Bar (int x) {
super(new Copier<Bar> () {
public Bar copy (Bar object) {
return new Bar(object.field);
}
});

Doesn't compile. Check your cut and paste, I found at least one other
syntax error in the code.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,009
Latest member
GidgetGamb

Latest Threads

Top