clone() vs copy constructor vs factory method?

2019-01-01 15:10发布

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 clone
10条回答
十年一品温如言
2楼-- · 2019-01-01 15:30

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

查看更多
看风景的人
3楼-- · 2019-01-01 15:34

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

查看更多
残风、尘缘若梦
4楼-- · 2019-01-01 15:39

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);
    }
}
查看更多
妖精总统
5楼-- · 2019-01-01 15:41

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: Deep copy, shallow copy, clone

查看更多
登录 后发表回答