Reputation: 179
I have an ArrayList a, which can contain objects of any type. I then need to loop through the elements of the ArrayList. If the element implements Cloneable, I need to clone the element (meaning make a copy of it and give it its own place in memory) and add the cloned element to ArrayList b. The problem is with casting. I need to cast to the right object type and then call clone(). (Because clone() in Object is protected.)
In the code below, I have managed to do that with a bunch of if statements. On each element, I say if Cloneable, and then nested in that if statement I have more if statements, checking for instance of the right type. When the program finds the right type, it casts and clones. All of this code works, but I would like a way to cast and then clone() without these if statements, since there could be classes I don't know of yet. Is there a way to do this? (I can cast using Class.cast() but I haven't had success calling clone() on such casts.)
I have tried to serialize the array list, implement my own interface (with a clone() method), and call a copy constructor. None of those work for every case. Near as I can tell, casting and then cloning is the only sure way to make it work. If there's a way to cast and clone without specifying the exact class, that will work for every case. Otherwise, I'm stumped and need another solution. (If there's a way to loop through every field in an object regardless of accessibility, that might work too.)
Here's my code:
// Establish variables
TestClass t = new TestClass();
TestClass u = new TestClass(1);
Point p = new Point();
Point q = new Point(1, 2);
// Set up ArrayList a
ArrayList a = new ArrayList();
a.add(t);
a.add(u);
a.add(p);
a.add(q);
// Get number of elements in a
int n = a.size();
// Set up ArrayList b
ArrayList b = new ArrayList();
// Clone all Cloneable elements from a into b
for (int i = 0; i < n; i++)
if (a.get(i) instanceof Cloneable)
if (a.get(i) instanceof TestClass)
b.add(((TestClass)a.get(i)).clone());
else if (a.get(i) instanceof Point)
b.add(((Point)a.get(i)).clone());
//ISSUE: I need to be able to cast and then clone based on the class a.get(i) represents, to avoid these if statements.
// Change initial variables. They change in ArrayList a (due to referencing the same memory) but not b
t.i = 2;
u.i = 3;
p.x = 3;
p.y = 4;
q.x = 5;
q.y = 6;
System.out.println(a);
System.out.println(b);
TestClass and Point are classes that I have written. They implement Cloneable.
Thank you for any help that is provided.
Upvotes: 1
Views: 402
Reputation: 3016
The whole clone mechanism in Java is basically broken. See for example http://www.artima.com/intv/issues3.html.
You could use a library which has all the functions in place (http://code.google.com/p/cloning/ - (Deep clone utility recomendation credits to Cojones ) or create a own interface like
public interface Copyable<T> {
T copy();
}
Let all classes you need implement that interface. If you know which class it is, you can just normally use it like
SomeClass a = new SomeClass();
SomeClass clone = a.copy();
Or if you only know that it is a Copyable:
Copyable<?> copy = x.copy();
But in most cases, it is better to use an existing solution like the libary above.
(Edit: It is always the best choice not to use javas own clone stuff :) )
Upvotes: 1
Reputation: 201439
I think you can do this using reflection,
if (a.get(i) instanceof Cloneable) {
Cloneable c = (Cloneable) a.get(i);
try {
Method cloneMethod = c.getClass().getMethod("clone", new Class<?>[] {});
cloneMethod.setAccessible(true);
Object clone = cloneMethod.invoke(c, new Object[] {});
b.add(clone);
} catch (Exception e) {
// Add real error handling.
e.printStackTrace();
}
} else {
// It isn't cloneable.
}
Upvotes: 1