Is the Java clone() method the only way to achieve polymorphic cloning?
Asked Answered
C

4

6

I need to equip my class with polymorphic cloning (deep copy), i.e. I need something like this to work:

SuperType original = new SubType();
SuperType copy = original.clone();

where original.clone() can be substituted by any mechanism to create a deep copy, and the actual type of copy shall be SubType, because original is also a SubType.

Is the clone() method and Cloneable interface the only way to achieve this? Factory methods and copy constructors cannot by used, since the actual class is known only in run time, right? Are there any other suggested methods except those serialize-deserialize approaches, and the Java deep-cloning library which is IMHO even worse black magic than the clone() method?

Thanks, Petr

Cinchonize answered 3/4, 2013 at 14:28 Comment(2)
You can't make a Constructor that the object you want to be cloned can be passed to?Jampacked
@gangqinlaohu Sure, I can, but then I would need to call new SubType(original) which I cannot since I do not know in time of writing the code if original is actually of class SubType, or SubType2, or SubSubType.Cinchonize
C
4

Actually Object's clone() method is not allowing you to do any polymorphic calling because is protected. Implementing Cloneable is of no use either because it doesn't contain a clone() method.

You can do polymorphic cloning by providing a polymorphic method for the cloned classes that in turn invoke the copy constructor.

abstract class SuperType {
    public SuperType(SuperType t) {
    }

    public abstract SuperType deepCopy();
}

class SomeType extends SuperType {

    SomeType(SomeType t) {
        //copy constructor
    }

    @Override
    public SomeType deepCopy() {                        
        return new SomeType(this);
    }
}

 ...

SuperType original = new SubType();
SuperType copy = original.deepCopy(); //the deepCopy is called on children classes

See also:

Joshua Block's opinion on cloning vs. copy constructor

Caseation answered 3/4, 2013 at 14:45 Comment(2)
OK, that would work. But in what sense is this different from using clone()? Isn't the deepCopy() method just a different name for it? Cannot the same things you do in deepCopy() be done in clone()?Cinchonize
@Cinchonize Cloning is a java "built in" way to provide object copies without the need of a copy constructor. It attempted to make life easier to programmers, but IMO it's not the case. Yes, if you take great care when overriding clone() (Joshua Block's Effectiva Java has a whole chapter about it), you should get the same results.Caseation
S
2

In order for your code to work, that code is either inside the SuperType class or subclass, or your SuperType type must have a public clone() method. A public clone() method does not exist automatically, and you must implement it. You could call it anything else for that matter, e.g. copy().

Your question then, is how to implement that clone() (or whatever you call it) method so that it does polymorphic cloning.

The way that was intended by the Java developers is to call super.clone(), assuming that all the classes in the inheritance hierarchy similarly implemented clone() to perform polymorphic cloning. This ultimately gets to the protected Object.clone() method, which does the magic of polymorphic cloning. Note that for Object.clone() to not throw an exception, your class must implement the Cloneable interface.

However, there are other possible ways. For example, assuming that all subclasses have a default constructor, you can do something like this.getClass().newInstance(). This will create an object of the right class, but the fields are not copied over. Your clone method will need to copy all the fields, and subclasses must override your clone method to copy their fields, etc. Note that it is irrelevant whether the Cloneable interface is implemented in this case.

Another way is, assuming that the class is Serializable, to serialize and unserialize this. This should create a polymorphic clone that has all the serializable fields carried over.

Slushy answered 3/4, 2013 at 23:20 Comment(0)
G
1

You can simply add a copy method to SuperType and implement it in all SubTypes

class SuperType {

    public SuperType copy() {
              ...
    }
}
Gordy answered 3/4, 2013 at 14:38 Comment(0)
L
0

If you don't like the Cloneable interface, you can create your own interface. Each class will be responsible for creating a new instance of the correct type.

Loralyn answered 3/4, 2013 at 14:42 Comment(2)
It is not about the fact that I do not like Clonable. I do not understand the dont-use-clone panic (probably I do not quite understand the issued related to clone despite I have read J. Bloch's book). Why shall devise my own interface basically for the same purpose as Clonable? Or would the purpose of my own interface be different from that of Clonable?Cinchonize
Well, your question was "Is the clone() method and Cloneable interface the only way to achieve this?". If the clone() method is ok for you, use it. However, using a custom interface allows you to take advantage of generics.Loralyn

© 2022 - 2024 — McMap. All rights reserved.