Reputation: 5953
I've seen defensive copies coded like this
void someMethod(Date d) {
myDate = new Date( d.getTime() );
}
But that doesn't make sense to me, isn't there a way in Java to create an identical copy in memory of that object?
I've read the clone()
will not work in all instances, but I don't understand why.
Upvotes: 1
Views: 2467
Reputation: 3986
I could try to answer this, but I'd just be plagiarizing Josh Bloch, so here's a link to the resource instead:
Copy Constructor versus Cloning
Bill Venners: In your book you recommend using a copy constructor instead of implementing
Cloneable
and writingclone
. Could you elaborate on that?Josh Bloch: If you've read the item about cloning in my book, especially if you read between the lines, you will know that I think clone is deeply broken. There are a few design flaws, the biggest of which is that the
Cloneable
interface does not have aclone
method. And that means it simply doesn't work: making somethingCloneable
doesn't say anything about what you can do with it. Instead, it says something about what it can do internally. It says that if by callingsuper.clone
repeatedly it ends up callingObject
'sclone
method, this method will return a field copy of the original.But it doesn't say anything about what you can do with an object that implements the
Cloneable
interface, which means that you can't do a polymorphicclone
operation. If I have an array ofCloneable
, you would think that I could run down that array and clone every element to make a deep copy of the array, but I can't. You cannot cast something toCloneable
and call theclone
method, becauseCloneable
doesn't have a publicclone
method and neither doesObject
. If you try to cast toCloneable
and call theclone
method, the compiler will say you are trying to call the protectedclone
method on object.The truth of the matter is that you don't provide any capability to your clients by implementing
Cloneable
and providing a publicclone
method other than the ability to copy. This is no better than what you get if you provide a copy operation with a different name and you don't implementCloneable
. That's basically what you're doing with a copy constructor. The copy constructor approach has several advantages, which I discuss in the book. One big advantage is that the copy can be made to have a different representation from the original. For example, you can copy aLinkedList
into anArrayList
.
Object
'sclone
method is very tricky. It's based on field copies, and it's "extra-linguistic." It creates an object without calling a constructor. There are no guarantees that it preserves the invariants established by the constructors. There have been lots of bugs over the years, both in and outside Sun, stemming from the fact that if you just callsuper.clone
repeatedly up the chain until you have cloned an object, you have a shallow copy of the object. The clone generally shares state with the object being cloned. If that state is mutable, you don't have two independent objects. If you modify one, the other changes as well. And all of a sudden, you get random behavior.There are very few things for which I use
Cloneable
anymore. I often provide a publicclone
method on concrete classes because people expect it. I don't have abstract classes implementCloneable
, nor do I have interfaces extend it, because I won't place the burden of implementingCloneable
on all the classes that extend (or implement) the abstract class (or interface). It's a real burden, with few benefits.Doug Lea goes even further. He told me that he doesn't use
clone
anymore except to copy arrays. You should useclone
to copy arrays, because that's generally the fastest way to do it. But Doug's types simply don't implementCloneable
anymore. He's given up on it. And I think that's not unreasonable.It's a shame that
Cloneable
is broken, but it happens. The original Java APIs were done very quickly under a tight deadline to meet a closing market window. The original Java team did an incredible job, but not all of the APIs are perfect.Cloneable
is a weak spot, and I think people should be aware of its limitations.
Upvotes: 7
Reputation: 89749
clone()
is only implemented meaningfully in some classes, because there are a lot of decisions involved in cloning that the JVM or the compiler doesn't make for you (e.g., shallow vs. deep copying). Some would also argue that the whole concept in Java is broken and therefore rarely used.
The end result, however, is that many classes cannot be cloned. In these cases, a user clones them by generating and initializing one object based on the other.
However, the Date
class implements Cloneable
, so there isn't really a benefit in this specific case compared to just using the "copy constructor".
One situation where cloning is preferable is when you are working with class hierarchies. Imagine you are representing a mathematical expression as a tree of Expression subtypes, where you reference the outermost expression.
Let's say that in this case it is a Plus. You would call clone on your reference to an Expression, but what you would really get is a new instance of Plus. With constructors you can't really do that because your Expression could be an interface or an abstract class.
Upvotes: 3
Reputation: 147164
From a mobile code security point of view, clone
can typically be overridden.
@Override public Date clone() {
return this; // Ha!
}
Even if you don't care about security, you could imagine a programmer being "clever" causing a bug report in your code.
The expectation that particularly clone
will return exactly the same runtime type also causes implementation problems.
Upvotes: 0
Reputation: 262534
There is no simple way to make an identical copy that always works.
Clone was supposed to do that, but it is not implemented by all classes and thus more or less broken.
Another approach would be to serialize/deserialize, but serialization is also not supported by all classes.
Upvotes: 1