tags:

views:

513

answers:

7

Once upon a time there was a class:

public class Scope<C extends Cloneable & Comparable<C>> implements Comparable<Scope<C>>, Cloneable, Serializable {

   private C starts;
   private C ends;
   ...

   @SuppressWarnings("unchecked")
   @Override
   public Object clone() {
       Scope<C> scope;
       try {
           scope = (Scope<C>) super.clone();
           scope.setStarts((C) starts.clone()); // The method clone() from the type Object is not visible
           scope.setEnds((C) ends.clone()); // The method clone() from the type Object is not visible
       } catch (CloneNotSupportedException e) {
           throw new RuntimeException("Clone not supported");
       }
       return scope;
   }
}

In Object we have:

protected native Object clone() throws CloneNotSupportedException;

And Cloneable interface is:

public interface Cloneable { 
}

How should I clone this?

Thanks in advance, Etam.

+1  A: 

This is one reason why no one likes Cloneable. It's supposed to be a marker interface, but it's basically useless because you can't clone an arbitrary Cloneable object without reflection.

Pretty much the only way to do this is to create your own interface with a public clone() method (it doesn't have to be called "clone()"). Here's an example from another StackOverflow question.

Michael Myers
It specifies an implementation behaviour (not a good one). Separating that junk from an interface of methods probably isn't a bad idea.
Tom Hawtin - tackline
A: 

As you see, if a class tries to implement Cloneable and you want a deep clone, then all of your constituent objects needs to be immutable, primitive, or need to also be Cloneable.

Often, a better and easier approach is to create a copy constructor.

public class Scope<C extends Comparable<C>> implements Comparable<Scope<C>>, Serializable {
    private C starts;
    private C ends;
    public Scope(final Scope original) {
       starts = new C(original.starts);
       ends = new C(original.ends);
       // initialize all my other fields from "original"
    }
}

and of course you need a copy constructor on C that is capable of handling polymorphism.

If you have no access or ability to modify the source to C, then any method of copying, no matter what the method, will be very difficult and potentially impossible. For example, it is not possible to make a copy of an enum instance.

Eddie
Yes, but the question is how to clone the generic parameter. There is no way to specify that a type must have a certain constructor.
Michael Myers
When I do that, I will have 2 references to the same starts object... Don't I?
etam
@etam: Of course not. That's why it's called a *copy* constructor.
Eddie
@Eddie: What if C won't have a copy constructor?
etam
It is not what I'm looking for :).
etam
A: 

Perhaps you meant ((C) starts).clone()

Peter Lawrey
That won't help. The problem is that clone() is not visible except to objects of the same type.
Michael Myers
The same error.
etam
+1  A: 

Slightly OT, but you could save yourself a lot of future grief with this:

   catch (CloneNotSupportedException e) {
       throw new RuntimeException("Clone not supported", e);
   }

So that when you get a stack trace you know which object caused the problem.

To answer the core question, your own interface that implements a public clone() as mmyers wrote and require that C extend that as well.

Yishai
It's not a good idea. I'd like to use Date for example. I don't wan't to extend every class I use.
etam
If you want this for types you don't control, reflection is your only option.
Yishai
+1  A: 

As a general comment, avoid using Object.clone() whenever possible. If you have control over the code in question, implement a copy constructor instead. See here for information.

Julien Chastang
+1. That's what I said.
Eddie
Yes, but there is no way to use an interface to specify a copy constructor. That means you have to actually know the type of the object to copy it.
Michael Myers
@mmyers: Sort of true; the alternative is reflection. However, with Cloneable you have other restrictions that can be just as difficult.
Eddie
But if you write your own interface, you don't have either problem. That's what I've been trying to say. (And implementations of the interface could easily delegate to a copy constructor if they wish.)
Michael Myers
@mmyers: True, if you make your own interface (such as the answer you linked to) and you have control over the source code, then you can easily make copies of objects known only by a generic type reference.
Eddie
@Eddie, @mmyers: All good comments. It seems to me that if you go the interface route, we should stay away from the "clone()" and "Cloneable" nomenclature for all the problems that we know about. It seems like "copy" and "Copyable" or some such would be better.
Julien Chastang
+2  A: 

I think the current green answer is bad , why you might ask?

  • It adds a lot of code
  • It requires you to list all fields to be copied and do this
  • This will not work for Lists when using clone() (This is what clone() for HashMap says: Returns a shallow copy of this HashMap instance: the keys and valuesthemselves are not cloned.) so you end up doing it manually (this makes me cry)

Oh and by the way serialization is also bad, you might have to add Serializable all over the place (this also makes me cry).

So what is the solution:

Java Deep-Cloning library The cloning library is a small, open source (apache licence) java library which deep-clones objects. The objects don't have to implement the Cloneable interface. Effectivelly, this library can clone ANY java objects. It can be used i.e. in cache implementations if you don't want the cached object to be modified or whenever you want to create a deep copy of objects.

Cloner cloner=new Cloner();
cloner.deepClone(someObject);

Check it out at http://robust-it.co.uk/clone/index.php

A: 

In addition to the "Java Deep Cloning Library" there's also the utility at http://www.genericdeepcopy.com/

Aaron