tags:

views:

1763

answers:

5

I did a quick google on implementing clone() in Java and found: http://www.javapractices.com/topic/TopicAction.do?Id=71

It has the following comment:

copy constructors and static factory methods provide an alternative to clone, and are much easier to implement.

All I want to do is make a deep copy. Implementing clone() seems to make a lot of sense, but this highly google ranked article makes me a bit afraid.

Here are the issues that I've noticed:

Copy constructors don't work with Generics.

Here's some pseudo-code that won't compile.

public class MyClass<T>{
   ..
   public void copyData(T data){
       T copy=new T(data);//This isn't going to work.    
   }
   ..
}

Sample 1: Using a copy constructor in a generic class.

Factory methods don't have standard names.

It's quite nice to have an interface for reusable code.

public class MyClass<T>{
    ..
    public void copyData(T data){
        T copy=data.clone();//Throws an exception if the input was not cloneable
    }
    ..
}

Sample 2: Using clone() in a generic class.

I noticed that clone is not a static method, but wouldn't it still be necessary to make deep copies of all the protected fields? When implementing clone(), the extra effort to throw exceptions in non-cloneable subclasses seems trivial to me.

Am I missing something? Any insights would be appreciated.

+2  A: 

Java doesn't have copy constructors in the same sense that C++ does.

You can have a constructor which takes an object of the same type as an argument, but few classes support this. (less than the number which support clone able)

For a generic clone I have a helper method which creates a new instance of a class and copies the fields from the original (a shallow copy) using reflections (actually something like reflections but faster)

For a deep copy, a simple approach is to serialize the object and de-serialize it.

BTW: My suggest is to use immutable objects, then you won't need to clone them. ;)

Peter Lawrey
+4  A: 

There is also the Builder pattern. See Effective Java for details.

I don't understand your evaluation. In a copy constructor you are fully aware of the type, why is there a need to use generics?

public class C {
   public int value;
   public C() { }
   public C(C other) {
     value = other.value;
   }
}

There was a similar question recently here.

public class G<T> {
   public T value;
   public G() { }
   public G(G<? extends T> other) {
     value = other.value;
   }
}

A runnable sample:

public class GenTest {
    public interface Copyable<T> {
        T copy();
    }
    public static <T extends Copyable<T>> T copy(T object) {
        return object.copy();
    }
    public static class G<T> implements Copyable<G<T>> {
        public T value;
        public G() {
        }
        public G(G<? extends T> other) {
            value = other.value;
        }
        @Override
        public G<T> copy() {
            return new G<T>(this);
        }
    }
    public static void main(String[] args) {
        G<Integer> g = new G<Integer>();
        g.value = 1;
        G<Integer> f = g.copy();
        g.value = 2;
        G<Integer> h = copy(g);
        g.value = 3;
        System.out.printf("f: %s%n", f.value);
        System.out.printf("g: %s%n", g.value);
        System.out.printf("h: %s%n", h.value);
    }
}
kd304
+1 this is the simplest but effective way to implement a copy constructor
dfa
Note that MyClass above is a generic, StackOverflow swallowed the <T>.
User1
Fixed your question formatting. Use four spaces on each line instead of pre+code tags.
kd304
+7  A: 

Basically, clone is broken. Nothing will work with generics easily. If you have something like this (shortened to get the point across):

public class SomeClass<T extends Copyable> {


    public T copy(T object) {
        return (T) object.copy();
    }
}

interface Copyable {
    Copyable copy();
}

Then with a compiler warning you can get the job done. Because generics are erased at runtime, something that does a copy is going to have a compiler warning generating cast in it. It is not avoidable in this case.. It is avoidable in some cases (thanks, kb304) but not in all. Consider the case where you have to support a subclass or an unknown class implementing the interface (such as you were iterating through a collection of copyables that didn't necessarily generate the same class).

Yishai
+1 for the Josh Bloch pointer on clone() :-).
Tom
shouldn't the return type of Someclass.copy() be T ?
matt b
It is also possible to do *without* compiler warning.
kd304
@kd304, if you mean that you supress the compiler warning, true, but really not different. If you mean you can avoid the need for a warning altogether, please elaborate.
Yishai
@Yishai: Look at my answer. And I wasn't referring to the suppresswarning.
kd304
A: 

What you are missing is that clone creates shallow copies by default and convention, and that making it create deep copies is, in general, not feasible.

The problem is that you cannot really create deep copies of cyclic object graphs, without being able to keep track what objects have been visited. clone() does not provide such tracking (as that would have to be a parameter to .clone()), and thus only creates shallow copies.

Even if your own object invokes .clone for all of its members, it still won't be a deep copy.

Martin v. Löwis
It may be infeasible to do deep-copying clone() for any arbitrary object, but in practice this is manageable for many object hierarchies. It just depends on what kinds of objects you have and what their member variables are.
Mr. Shiny and New
A: 

One pattern that may work for you is bean-level copying. Basically you use a no-arg constructor and call various setters to provide the data. You can even use the various bean property libraries to set the properties relatively easily. This isn't the same as doing a clone() but for many practical purposes it's fine.

Mr. Shiny and New