views:

134

answers:

6

its easier to explain in code so here

Object anObj;
anObj = new MyObj();
anObj = new Rectangle();
anObj.clone();//this doesnt exist because its on the root Object class

what can i use instead of the Object.clone() method in this example?

----------------------- extra info ------------------------------

I have added extra info but it seems to have gone in the middle of all the answers, so here it is again so it can be read.

Hi all these are all really helpful on topic of cloning or copying, which i now need to think about. but they dont help with the initial question. maybe more info from me will help you understand what im after.

I am overriding the clone for each of my objects and adding all the other clone and copy methods needed to completely clone the object, this includes adding a custom method to copy a bufferedimage. ie:-

public Object clone() {//i copied from 'thelost's answer
    try { 
        CloningExample copy = (CloningExample)super.clone(); 
        copy.names = (LinkedList)names.clone(); 
        return copy; 
    } catch (CloneNotSupportedException e) { 
        return null; 
    } 
}

but i have one variable in my class that is an Object but because it hold various other objects of different types, each of my types will have a clone method, but short of checking if its each of my types and then calling clone() on my type, which would be very long as i have many types, i cannot see how to copy or clone the object easily. is there a way os should i just write a static method like this?

static findTypeAndCopy(Object thisobj){ 
    if(thisobj==null) 
        return null;

    if(thisobj instanceOf MyObj1){ 
        return ((MyObj1)thisobj).clone(); 
    }else if(thisobj instanceOf MyObj2){ 
        return ((MyObj2)thisobj).clone(); 
    ... 
    etc
}

???

A: 

You could check whether it implements the Cloneable interface and if it does then use the clone method.

And here is and example on how to implement it yourself.

thelost
Really, you don't want the `Cloneable` evil magic.
Tom Hawtin - tackline
A: 

As others have said: Clonable is broken and you should consider other options such as copy constructors. Having said that, here is a solution that should work if you really must use clone():

Object clone = null;
if(anObj instanceof Clonable) {
    Method cloneMethod = anObj.getClass().getMethod("clone");
    /*
     * TODO: Handle the case where an object is cloneable but 
     * does not have a public clone() method.
     */
    clone = cloneMethod.invoke(anObj);
} else {
    throw new RuntimeException("can't clone object");
}

Or you could use reflection to clone the object field by field, if it does not implement clone()... Get all fields, copy the values to the new object. But this is tricky, if the object has no no-arg constructor.

Thomas Lötzer
It won't work. `Cloneable` interface doesn't have method `clone`.
Tadeusz Kopec
@Tadeusz Kopec You're right, updated the answer with a solution that should work.
Thomas Lötzer
A: 

You can't know for sure that a class has the capacity to clone because clone() is a method from Object. The best you can do is to check if the class is Cloneable. Usually when a class is Cloneable it means that the developer overrode the clone() method.

But even so, Object can't call this method.

There is the reflection solution. But as the doc says :

Even if the clone method is invoked reflectively, there is no guarantee that it will succeed.

You can read documentation here, and there is a statement from Josh Bloch on this class (last paragraph).

Colin Hebert
And how did you make compiler accept call of protected method?
Tadeusz Kopec
You can't. When you implement Cloneable you have to use a public modifier so everyone can use it.
Colin Hebert
@Colin: THAT DOESN'T WORK! `Cloneable` is broken.
polygenelubricants
@Colin HEBERTNo. You "should", according to the documentation. And even if the method is public on your class: The variable is of type Object, so the method is protected. You need to use reflection to get the method reference and invoke it.
Thomas Lötzer
@polygenelubricants, @Thomas You're right. I forgot that part. I'll edit the answer.
Colin Hebert
+4  A: 

The best idea is to avoid cloning, as it is broken.
Cloneable interface doesn't have method clone. Method clone is defined as protected in Object class. So to call clone you need to know the type of object to have access to clone. Better idea is either copy constructor (as Bloch recommends) or serialization and deserialization (via XML for example).
Maybe you can gain access to clone with reflection, but I'm not sure. And I discourage it.

Tadeusz Kopec
I agree that clone is broken, but using reflection to work arround is a bad idea.
Chris
[Java Practices -> Copy Constructor](http://www.javapractices.com/topic/TopicAction.do?Id=12)
Andreas_D
@Chris I agree it's a bad idea. But if f1wade wants to invoke it without knowing object's type, it's the only possibility.
Tadeusz Kopec
@Chris - It's better to say the Cloneable is broken. You should still use clone() to copy arrays (for example).
Skip Head
+4  A: 

You seem to have realized that Cloneable in Java is broken.

Here are some quotes from an interview with Josh Bloch, author of Effective Java 2nd Edition:

If you've read the item about cloning in my book, especially if you read between the lines, you will know that I think clone is deeply broken. There are a few design flaws, the biggest of which is that the Cloneable interface does not have a clone method. And that means it simply doesn't work: making something Cloneable doesn't say anything about what you can do with it. Instead, it says something about what it can do internally. It says that if by calling super.clone repeatedly it ends up calling Object's clone method, this method will return a field copy of the original.

But it doesn't say anything about what you can do with an object that implements the Cloneable interface, which means that you can't do a polymorphic clone operation.

Here are some quotes from the book, Item 11: Override clone judiciously:

[...] you are better off providing alternative means of object copying, or simply not providing the capability.

[...] A fine approach to object copying is to provide copy constructor or copy factory. A copy constructor is simply a constructor that takes a single argument whose type is the class containing the constructor:

public Yum(Yum yum);

A copy factory is the static factory analog of a copy constructor:

public static Yum newInstance(Yum yum);

Related questions


Alternative: Cloneable 2.0

If you really insist on having a Cloneable-like functionality that isn't broken, you can write something like this (generified for extra jazz):

public class DupableExample {

    interface Dupable<T> {
        T dup();
    }   
    static class Sheep implements Dupable<Sheep> {
        Sheep(Sheep sheep) { }
        @Override public Sheep dup() {
            return new Sheep(this);
        }
    }
    public static void main(String[] args) {
        Dupable<?> dupable = new Sheep(null);
        System.out.println(dupable);
        System.out.println(dupable.dup());

        // no cast needed
        Sheep dolly2 = new Sheep(null).dup();
    }
}

The output should be something like this (as seen on ideone.com):

DupableExample$Sheep@{some hexadecimal code}
DupableExample$Sheep@{a different hexadecimal code, in all likelyhood}

So now given any Dupable<T>, you can invoke T dup() on it to get what you expect is a duplicate copy.

This is just a proof-of-concept: in actual implementation, your copy constructor/copy factory/whatever copy mechanism will actually have the copying logic implemented, and Dupable<T> would be a public top-level interface.

polygenelubricants
A: 
interface PublicCloneable extends Cloneable{
    public Object clone();
}

class MyObject implements PublicCloneable {
    public Object clone() {
        return super.clone();
    }
}

class MainObject {
    public static void main(String[] params) {
        Object m = new MyObject();

        if (m instanceof PublicCloneable) {
            Object c = m.clone();
        }
    }
}
Max