0

When searching the net for possibilities how to make a deep copy of an object polymorphically, I found a solution that claims to solve many issues with the clone() method, e.g. the impossibility to clone final fields. The solution combines the use of a protected copy constructor inside the clone() implementation and basically goes like this (example copied from the referenced page):

public class Person implements Cloneable
{
    private final Brain brain; // brain is final since I do not want 
                               // any transplant on it once created!
    private int age;

    public Person(Brain aBrain, int theAge)
    {
        brain = aBrain; 
        age = theAge;
    }

    protected Person(Person another)
    {
        Brain refBrain = null;
        try
        {
            refBrain = (Brain) another.brain.clone();
            // You can set the brain in the constructor
        }
        catch(CloneNotSupportedException e) {}
        brain = refBrain;
        age = another.age;
    }

    public Object clone()
    {
        return new Person(this);
    }

    …
}

The clone() method of Brain may be implemented in a similar way.

Based on the documentation of the clone() method, it seems that all "contracts" of this method 'are not absolute requirements' and that 'the returned object should be obtained by calling super.clone()' is just a convention.

So, is this implementation actually incorrect? Why?

And if it is correct, why it did not become a design pattern? What are the downsides of this???

Thanks, Petr

Posa
  • 320
  • 3
  • 8
  • I don't understand why not simply use "new Person(this.brain, this.age)" (if attributes are final) or "new Person(this.brain.clone(),this.age) in other case – Pablo Lozano Apr 03 '13 at 15:40
  • `clone()` is broken enough that you should just use copy constructors everywhere and completely stop writing `clone` methods. – Louis Wasserman Apr 03 '13 at 17:07
  • I have never understood why you need either of them. You need copy constructors in C++ because the compiler generates calls to them, and occasionally you even need to write them yourself. Ultimately this is because the default C++ argument semantic is object-by value. But in nearly 16 years of Java I have never used either `clone()` or a copy constructor in any serious code. – user207421 Apr 04 '13 at 03:12
  • @PabloLozano Your suggestions are OK, if I knew that the thing I want to clone is actually a Person. I said I need a polymorphic cloning. What if the real instance that shall be cloned is actually a subclass of Person? Then using this implementation of this polymorphic clone method will call the right copy constructor of the actuall class, not the copy constructor of Person. When using copy constructors only I would need to know the real class that shall be created already in time of writing the code, but the real class is known only in runtime. – Posa Apr 04 '13 at 16:34
  • @LouisWasserman Louis, read the above response to Pablo Lozano, it applies to your suggestion as well. Thanks. – Posa Apr 04 '13 at 16:35
  • @EJP If you virtually never use neither copy constructors, nor clone(), how do you suggest to make copies of objects? Thank you very much! – Posa Apr 04 '13 at 16:36
  • @Posa I've never needed to make a copy of an object other than as I described above. Why do you think you do? – user207421 Apr 05 '13 at 01:26
  • @EJP Sorry, I am not sure I understand you. Above you say that in 16 years of Java you have never used either clone() or copy constructors. You do not describe anything else. Shall I understand from this that you never needed to make a copy of an object? – Posa Apr 05 '13 at 12:52

3 Answers3

1

You are trying to clone by implementing cloneable interface but not following recommended contracts of cloning.

You are basically creating new object using copy constructor, my question is then why do you need to implement cloneable?

If you are implementing cloneable then you must respect the contracts. When you use copy constructor inside clone method then i will not recommend this approach simply because clone of it child class will not be an object of child class and intstead will be an object of Person class.

Also want to point out that, using copy constructor instead of cloneable interface is more object oriented approach.

Lokesh
  • 7,810
  • 6
  • 48
  • 78
  • One part of my problem is that it is completely unclear to me, what the contracts of clone() and Cloneable are. In the documentation, everything that looks like their contract is then somehow weakened by saying "but it is not an absolute requirement" or something like this. So, what is actually the contract of clone() and Clonable? Regarding the question "Why do I need clone() when basically using the copy constructor": because I need a polymorphic cloning behavior. I do not know in time of writing the code what the actual class that should be instantiated is. – Posa Apr 04 '13 at 16:45
  • Ok agreed its not an absolute requirement but when people are going to use your code they will expect on those lines [which is why we have contracts]. Secondly how does it help to mix clone and copy constructor? I think it just makes things complicated for you. You can achieve polymorphic behaviour with copy constructor but all i am saying it dont club it with cloning as it will only create confusion. – Lokesh Apr 04 '13 at 16:54
  • How can I make a copy constructor polymorphic? It has a different name for each class. Can you give me a brief example? – Posa Apr 05 '13 at 12:55
  • Here is an example: 1. Create Interface : public interface myCloner { public myCloner getClone(); } . Now implement this in your class hierarchy , all the classes will implement this method and will return a new object using copy constructor inside the method. Java supports covariant return types so you can return specific objects. All i have done is created my own interface to by pass contracts of cloneable and rest is staright forward. – Lokesh Apr 05 '13 at 16:26
0

So, is this implementation actually incorrect? Why?

It's not safe because CloneNotSupportedException is dropped.

If Brain is not clonable new Person will have no brain :) What if there is an object in your object structure that you are not controlling (no access to sources)?

why it did not become a design pattern

Because not all objects can be cloned just from the similar object. Usually, there are environment objects that known better what this particular new object will look like rather then its existing neighbor object.

Vitaly
  • 2,760
  • 2
  • 19
  • 26
0

The downside of this method (beside the fact that a CloneNotSupportedException is dropped) is that if subclasses call super.clone() they will get an instance of Person instead of an instance of their own class as they may expect.

Your method is OK if you know that subclasses will not rely on Object.clone() (or if there is no subclass)

WilQu
  • 7,131
  • 6
  • 30
  • 38
  • So, you basically say that I should not mix the approach of clone() and Clonable with something different, since I cannot ensure that users of my class will use the same approach as I do, right? – Posa Apr 04 '13 at 16:40
  • Yes, when you implement clone(), you do it usually by calling super.clone(). If you don't do that, be sure that it is well documented because subclasses won't be able to do that either. – WilQu Apr 05 '13 at 07:20