clone() vs copy constructor vs factory method?

JavaClone

Java Problem Overview


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.

Java Solutions


Solution 1 - Java

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).

Solution 2 - Java

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);
    }
}

Solution 3 - Java

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. ;)

Solution 4 - Java

I think Yishai answer could be improved so we can have no warning with the following code:

public class SomeClass<T extends Copyable<T>> {

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

interface Copyable<T> {
    T copy();
}

This way a class that need to implements Copyable interface has to be like this:

public class MyClass implements Copyable<MyClass> {

	@Override
	public MyClass copy() {
		// copy implementation
		...
	}
	
}

Solution 5 - Java

Below are some cons due to which many developers don't use Object.clone()

  1. Using Object.clone() method requires us to add lots of syntax to our code like implement Cloneable interface, define clone() method and handle CloneNotSupportedException and finally call to Object.clone() and cast it our object.
  2. Cloneable interface lacks clone() method, it is a marker interface and doesn’t have any method in it, and still we need to implement it just to tell JVM that we can perform clone() on our object.
  3. Object.clone() is protected so we have to provide our own clone() and indirectly call Object.clone() from it.
  4. We don’t have any control over object construction because Object.clone() doesn’t invoke any constructor.
  5. If we are writing clone() method in a child class e.g. Person then all of its superclasses should define clone() method in them or inherit it from another parent class otherwise super.clone() chain will fail.
  6. Object.clone() support only shallow copy, so reference fields of our newly cloned object will still hold objects which fields of our original object was holding. In order to overcome this, we need to implement clone() in every class who’s reference our class is holding and then clone them separately in our clone() method like in below example.
  7. We can not manipulate final fields in Object.clone() because final fields can only be changed through constructors. In our case, if we want every Person object to be unique by id, we will get the duplicate object if we use Object.clone() because Object.clone() will not call the constructor and final id field can’t be modified from Person.clone().

Copy constructors are better than Object.clone() because they

  1. Don’t force us to implement any interface or throw any exception but we can surely do it if it is required.
  2. Don’t require any casts.
  3. Don’t require us to depend on an unknown object creation mechanism.
  4. Don’t require parent class to follow any contract or implement anything.
  5. Allow us modify final fields.
  6. Allow us to have complete control over object creation, we can write our initialization logic in it.

Read more on Java Cloning - Copy Constructor versus Cloning

Solution 6 - Java

Usually, clone() works in tandem with a protected copy constructor. This is done because clone(), unlike a constructor, can be virtual.

In a class body for Derived from a super class Base we have

class Derived extends Base {
}

So, at its most simplistic, you would add to this a virtual copy constructor with the clone(). (In C++, Joshi recommends clone as the virtual copy constructor.)

protected Derived() {
    super();
}

protected Object clone() throws CloneNotSupportedException {
    return new Derived();
}

It gets more complicated if you want to call super.clone() as is recommended and you have to add these members to the class, you can try this

final String name;
Address address;

/// This protected copy constructor - only constructs the object from super-class and
/// sets the final in the object for the derived class.
protected Derived(Base base, String name) {
   super(base);
   this.name = name;
}

protected Object clone() throws CloneNotSupportedException {
    Derived that = new Derived(super.clone(), this.name);
    that.address = (Address) this.address.clone();
}

Now, if an execution, you got

Base base = (Base) new Derived("name");

and you then did

Base clone = (Base) base.clone();

this would invoke, clone() in the Derived class (the one above), this would invoke super.clone() - which may or may not be implemented, but you're advised to call it. The implementation then passes output of super.clone() to a protected copy constructor that takes a Base and you pass any final members to it.

That copy constructor then invokes the copy constructor of the super-class (if you know that it has one), and sets the finals.

When you come back to the clone() method, you set any non-final members.

Astute readers will notice that if you have a copy-constructor in the Base, it will be called by super.clone() - and will be called again when you invoke the super-constructor in the protected constructor, so you may be calling the super copy-constructor twice. Hopefully, if it is locking resources, it will know that.

Solution 7 - Java

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.

Solution 8 - Java

The Cloneable interface is broken, in the sense that it is useless but clone works well and can lead to better performance for big objects - 8 fields and more, but it will then fail the escape analysis. so preferable to use copy constructor most of the time. Using clone on array is faster than Arrays.copyOf because the length is guaranteed to be the same.

more details here https://arnaudroger.github.io/blog/2017/07/17/deep-dive-clone-vs-copy.html

Solution 9 - Java

If one is not 100% aware of all the quirks of clone(), then I would advise to stay away from it. I would not say that clone() broken. I would say: use it only when you are entirely sure it is your best option. A copy constructor (or factory method, that doesn't really matter I think) is easy to write (maybe lengthy, but easy), it only copies what you want to be copied, and copies the way you want things to be copied. You can trim it to your exact needs.

Plus: it's easy to debug what happens when you call your copy constructor / factory method.

And clone() does not create a "deep" copy of your object out of the box, assuming you mean that not only the references (e.g. to a Collection) are copied over. But read more about deep and shallow here: https://stackoverflow.com/questions/6182565/deep-copy-shallow-copy-clone

Solution 10 - Java

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.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionUser1View Question on Stackoverflow
Solution 1 - JavaYishaiView Answer on Stackoverflow
Solution 2 - JavaakarnokdView Answer on Stackoverflow
Solution 3 - JavaPeter LawreyView Answer on Stackoverflow
Solution 4 - JavaAlepacView Answer on Stackoverflow
Solution 5 - JavaNaresh JoshiView Answer on Stackoverflow
Solution 6 - JavaBonaparteView Answer on Stackoverflow
Solution 7 - JavaMr. Shiny and New 安宇View Answer on Stackoverflow
Solution 8 - Javauser3996996View Answer on Stackoverflow
Solution 9 - JavasorrymissjacksonView Answer on Stackoverflow
Solution 10 - JavaMartin v. LöwisView Answer on Stackoverflow