Cloneable type parameter?

S

Stefan Schmiedl

Greetings.

I'd like to define a wrapper class, whose instances keep read-only
copies of the original object passed in. I tried using generics for this:


public class RestorableObject<T> {

private T original;
private T workingCopy;

public RestorableObject(T obj) {
original = obj;
workingCopy = obj.clone(); // clone() is protected in Object
}

}


After RTFM on how generics actually work, the error message is explainable:
T is unbounded, so the compiler sees me calling a protected method outside
of its class.

So here is my next attempt:


public class RestorableObject<T extends Cloneable> {

private T original;
private T workingCopy;

public RestorableObject(T obj) {
original = obj;
workingCopy = obj.clone(); // clone() not found in Cloneable
}

}


I should have seen this coming, since Cloneable is an empty interface,
and the docs state that

* By _convention_, classes that implement this interface should override
* Object.clone (which is protected) with a public method.

I guess nobody told javac about this _convention_ ... must be human thing.

I would like to make the compiler ensure that RestorableObject is
only wrapped around objects providing a clone() method. I can do
this by introducing an interface


public interface ReallyCloneable<T> {
public T clone();
}


and finally arriving at


public class RestorableObject<T extends ReallyCloneable<T>> {

private T original;
private T current;

public RestorableObject(T obj) {
original = obj;
current = obj.clone();
}

}


Is there a more elegant way of doing this?

Regards,
Stefan
 
D

Daniel Dyer

I should have seen this coming, since Cloneable is an empty interface,
and the docs state that

* By _convention_, classes that implement this interface should override
* Object.clone (which is protected) with a public method.

I guess nobody told javac about this _convention_ ... must be human
thing.

I would like to make the compiler ensure that RestorableObject is
only wrapped around objects providing a clone() method. I can do
this by introducing an interface

Cloning in Java was not very well thought-out. You could use reflection
to invoke the clone method.

Dan.
 
M

Mike Schilling

Daniel Dyer said:
Cloning in Java was not very well thought-out. You could use reflection
to invoke the clone method.

Note, though, that clone() (by default, at least) is a shallow clone, so
changes made to objects that are fields of your working copy may not be
undone by reverting to your original. What might work better for you
(depending on your requirements, which are unstated) is to save the object
by writing it to a DataOutputStream, and restoring it by reading it back
from that stream. This will do the equivalent of a deep clone, and works
for many objects that do not implement Clonable.
 
S

Stefan Schmiedl

Note, though, that clone() (by default, at least) is a shallow clone, so
changes made to objects that are fields of your working copy may not be
undone by reverting to your original. What might work better for you
(depending on your requirements, which are unstated) is to save the object
by writing it to a DataOutputStream, and restoring it by reading it back
from that stream. This will do the equivalent of a deep clone, and works
for many objects that do not implement Clonable.

That's a nice idea, actually. Especially since I could tweak my
program so that I would need to do this only once per session.

Thanks,
s.
 
T

Thomas Weidenfeller

Stefan said:
Greetings.

I'd like to define a wrapper class, whose instances keep read-only
copies of the original object passed in. I tried using generics for this:


public class RestorableObject<T> {

private T original;
private T workingCopy;

public RestorableObject(T obj) {
original = obj;
workingCopy = obj.clone(); // clone() is protected in Object
}

}

You need to use reflection to verify if T has an accessible clone()
method and invoke the method if you can get hold of one. The
serialization trick will not help much. You have to check if the object
is serializable. Anyhow using serialization is likely a great waste of
CPU cycles.

In both cases you are faced with another problem: What if T does not
provide clone() (or serialization)? Error message? Gamble and use the
original reference? Throw an exception? You decide.

In short, generics and cloning don't work well together. Yet another
reason why IMHO generics are am ugly, not well thought-out hack. clone()
was always a strange hack, and with generics two hacks collide.

/Thomas
 
M

Mike Schilling

In both cases you are faced with another problem: What if T does not
provide clone() (or serialization)? Error message? Gamble and use the
original reference? Throw an exception? You decide.

In short, generics and cloning don't work well together. Yet another
reason why IMHO generics are am ugly, not well thought-out hack. clone()
was always a strange hack, and with generics two hacks collide.

Not to defend generics, but if Clonable sensibly provided a public clone()
method, the generics approach would work as expected.
 
S

Stefan Schmiedl

Not to defend generics, but if Clonable sensibly provided a public clone()
method, the generics approach would work as expected.

Some of these thoughts have occurred to me, too.
But you know, when in Rome, don't complain about linguam latinam :)

s.
 
T

Thomas Weidenfeller

Mike said:
Not to defend generics, but if Clonable sensibly provided a public clone()
method, the generics approach would work as expected.

You would still have to have the first problem, an unchecked cast and
you either have to suppress or ignore the warning:

class CloneMe<T> implements Cloneable {
public CloneMe<T> clone() {
CloneMe<T> c = (CloneMe<T>) super.clone(); // BANG!

:
.
}
}

The problem is the call to super.clone(). And you would still need
another unchecked cast for every instance you want to deep-clone.


/Thomas
 

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

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,578
Members
45,052
Latest member
LucyCarper

Latest Threads

Top