11

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?

Etam
  • 4,553
  • 10
  • 40
  • 60
  • I don't quite understand the question. Does not Scope already have a clone() method? – Journeyman Programmer Apr 29 '09 at 19:59
  • 2
    Generics don't play into this problem. What if `start` and `ends` were some specific type that implemented `Cloneable`, but didn't widen the accessibility to "public". You'd have the same problem. – erickson Apr 29 '09 at 20:00

6 Answers6

11

Solution

Use the 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();
XX clone = cloner.deepClone(someObjectOfTypeXX);

Addendum

A previous answer had the following drawbacks:

  • 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(); the clone() for HashMap notes: Returns a shallow copy of this HashMap instance: the keys and values themselves are not cloned, so you end up doing it manually.

Serialization is also bad because it may require adding Serializable everywhere.

Dave Jarvis
  • 30,436
  • 41
  • 178
  • 315
Cojones
  • 1,906
  • 22
  • 25
  • 2
    A semantically-correct clone operation must replace all fields which encapsulate the state of a mutable object with a copy of that object, but must *not* do so with fields that encapsulate the *identity* of an object (objects which contain any fields which encapsulate both the mutable state and identity of the target cannot be correctly cloned in isolation; it may be possible to clone a group of such objects, but doing so correctly requires an understanding of the relationship between them). If an object will never be modified, whether or not the type is immutable, deep cloning... – supercat Sep 13 '12 at 22:42
  • 2
    ...will be wasteful but (unless object identity is important) will not affect correctness. I'm not quite clear how useful a deep cloning utility is apt to be in general unless it is used with classes that tag the fields which need copying, since the need to deep-clone fields is a function of how fields are used, and not the type thereof. – supercat Sep 13 '12 at 22:46
5

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.

Community
  • 1
  • 1
Michael Myers
  • 188,989
  • 46
  • 291
  • 292
4

Hopefully I've resolved the problem of generic cloning in Java:

public class Generic<T> {
  private T data;

  public Generic() {
    // ...
  }

  @SuppressWarnings("unchecked")
  @Override
  public Object clone() {
    Generic<T> cloned = new Generic<T>();
    try {
      cloned.data = (T) data.getClass().getMethod("clone").invoke(data);
    } catch (Exception e) {
      // ...
    }
    return cloned;
  }
}
Istvan
  • 41
  • 1
  • I did not try exactly this snippet, but I reused this idea to solve another task. I wanted to create such a "polymorphic" static method in the base generic class which returns the object of the derived generic class (depending on which derived class calls it). I did it so and it works: public static > E cloneGeneric(E obj) { E v_res = null; try { System.out.println("Cloning " + obj.getClass()); // displays derived class v_res = (E) obj.getClass().getMethod("clone").invoke(obj); } catch (Exception e) { /*...*/ } return v_res; } – Alexander Samoylov May 22 '19 at 20:25
2

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
  • 90,445
  • 31
  • 189
  • 263
  • 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 Apr 29 '09 at 21:28
  • If you want this for types you don't control, reflection is your only option. – Yishai Apr 29 '09 at 22:03
1

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.

Community
  • 1
  • 1
Julien Chastang
  • 17,592
  • 12
  • 63
  • 89
  • 1
    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 Apr 29 '09 at 20:56
  • 1
    @mmyers: Sort of true; the alternative is reflection. However, with Cloneable you have other restrictions that can be just as difficult. – Eddie Apr 29 '09 at 21:24
  • 1
    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 Apr 29 '09 at 21:29
  • 1
    @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 Apr 29 '09 at 22:04
  • @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 Apr 30 '09 at 17:33
-1

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
  • 53,828
  • 22
  • 125
  • 145