[java] Cloning lists

Started by
10 comments, last by Zbyl 18 years, 1 month ago
I know this is a rather stupid question, but can't find and google solution by myself: I want to make a list of cloned elements from another list. The following code doesn't work, obviously: List<T> list; List<T> clones = new ArrayList<T>; for(T t : list) clones.add((T)t.clone()); neither does this (also obviously): List<T> list; List<T> clones = new ArrayList<T>; for(T t : list) clones.add((T)((Cloneable)t).clone()); Any suggestions?
Advertisement
Please specify why code "does not work". Does it not compile? Does it throw an exception at runtime? Unexpected results? An accurate error description like the pasted compiler error or the exception message?

Your first code sample should work except for the fact that your new list is not necessairily of the same type as the source list (use either clone() and remove the elements because they are not deep-copied by default or use reflection to discover the class of the source list).
Looking at your second code fragment, I get the suspicion that your list elements simply cannot clone themselves. In this case, modify their class accordingly.
The code does not work, because the method clone() is not in the Clonable interface, and Object.clone() is protected.
I need code that would copy the list of T's (for any T that implements Clonable interface and has a public clone() method).

I thought I could get the object's class, ask it (via reflection) for a "clone" method, and invoke it. But is it the "right" way to do it?
Quote:Original post by Zbyl
The code does not work, because the method clone() is not in the Clonable interface, and Object.clone() is protected.
I need code that would copy the list of T's (for any T that implements Clonable interface and has a public clone() method).

What about...

[source=java]interface TrulyCloneable {    public Object clone() throws CloneNotSupportedException;}class Foo implements Cloneable, TrulyCloneable {    @Override    public Object clone() throws CloneNotSupportedException {        return super.clone();    }}//--------------------------------------------------public class CopyExample {    public static void main(String[] args) {                List<TrulyCloneable> list = new ArrayList<TrulyCloneable>();        List<TrulyCloneable> clones = new ArrayList<TrulyCloneable>();                list.add(new Foo());        list.add(new Foo());        list.add(new Foo());                for(TrulyCloneable t : list)            try {                clones.add((TrulyCloneable)t.clone());            }            catch (CloneNotSupportedException e) {                e.printStackTrace();            }        for(int i = 0; i < list.size(); i++)            System.out.println(list.get(i) == clones.get(i));           }    }

Does the 'java.util.Collections' class has method to deal with copying? (and copying with clone() of elements data, btw?)

Son Of Cain
a.k.a javabeats at yahoo.ca
Quote:Original post by Zbyl
List<T> list;

Any suggestions?

How about this?

List<T extends Cloneable> list;
This:
List<T extends Cloneable> list;
won't work, cause, like I said, Clonable interface is empty.

'java.util.Collections' does not have any methods for cloning.

The 'TrulyCloneable' solution is not good enough either, cause I want the clone_list to work with any class implementing public clone() method.
In C++ with templates it would be very easy, and I hoped that in Java with generics it would be doable too...

So the only solution that works uses reflection:
[source=java]public static <T> List<T> clone_list(List<? extends T> list) throws Exception{    ArrayList<T> out = new ArrayList<T>();    for(T t : list)    {        Method m = t.getClass().getMethod("clone");        out.add((T)m.invoke(t)); //WARNING:        //Type safety: The cast from Object to T is actually checking        //against the erased type Object    }    return out;}

But can anyone explain me where the warning comes from?
Quote:Original post by Zbyl
But can anyone explain me where the warning comes from?

It seems to be marked as a bug in the Eclipse compiler. You can suppress the warning with:
@SuppressWarnings("unchecked")



Edit: Hmm, it seems the warning is shown because of the downcast... http://www.angelikalanger.com/GenericsFAQ/FAQSections/ParameterizedTypes.html

[Edited by - RayNbow on March 18, 2006 11:28:02 AM]
According to the J2SE 5 API spec:

(From the Cloneable interface)
By convention, classes that implement this interface should override Object.clone (which is protected) with a public method.

You just need to implement your own clone() method and call on it. You can always make a method more public, but not more private.
This is similar to the equals() method or hashcode(). The default implementation rarely is sufficient for most cases.
Quote:Original post by Whackjack
According to the J2SE 5 API spec:

(From the Cloneable interface)
By convention, classes that implement this interface should override Object.clone (which is protected) with a public method.

You just need to implement your own clone() method and call on it. You can always make a method more public, but not more private.
This is similar to the equals() method or hashcode(). The default implementation rarely is sufficient for most cases.


That doesn't help him very much, because his code must work on type Object and that class doesn't define clone() as a public method.

The Cloneable interface is one of the big design monsters present in the java library. The only sensible thing you can do with it is ignore it and create your own Copyable interface. If this is not an option for the original poster, no other solution than using reflection comes to mind. (If there would be an alternative solution, it would in a sense represent another one of java's big failures)

This topic is closed to new replies.

Advertisement