У меня есть ArrayList a, который может содержать объекты любого типа. Затем мне нужно перебрать элементы массива ArrayList. Если элемент реализует Cloneable, мне нужно клонировать элемент (что означает сделать его копию и присвоить ему свое место в памяти) и добавить клонированный элемент в ArrayList b. Проблема заключается в кастинге. Мне нужно указать правильный тип объекта, а затем вызвать clone(). (Потому что clone() в объекте защищен.)
В приведенном ниже коде мне удалось сделать это с помощью нескольких операторов if. На каждом элементе я говорю, если Cloneable, а затем вложен в этот оператор if, у меня есть другие операторы if, проверяющие, например, правильный тип. Когда программа находит нужный тип, она бросает и клонирует. Весь этот код работает, но я хотел бы использовать метод cast и then clone() без этих операторов if, поскольку могут быть классы, о которых я еще не знаю. Есть ли способ сделать это? (Я могу использовать класс Class.cast(), но у меня не было успеха при вызове clone() для таких приведений.)
Я попытался сериализовать список массивов, реализовать свой собственный интерфейс (с помощью метода clone()) и вызвать конструктор копирования. Ни одно из них не работает для каждого случая. Близко, как я могу судить, кастинг, а затем клонирование - единственный верный способ заставить его работать. Если есть способ бросить и клонировать без указания точного класса, это будет работать для каждого случая. В противном случае я в тупик и нуждаюсь в другом решении. (Если есть способ перебрать все поля в объекте независимо от доступности, это тоже может работать.)
Вот мой код:
// 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 и Point - это классы, которые я написал. Они реализуют Cloneable.
Спасибо за любую помощь, которая предоставляется.
Весь механизм клонирования в Java в основном нарушен. См. Например, http://www.artima.com/intv/issues3.html.
Вы можете использовать библиотеку, которая имеет все функции на месте (http://code.google.com/p/cloning/ - (рекомендации по использованию утилиты Deep clone для Cojones) или создать собственный интерфейс, например
public interface Copyable<T> {
T copy();
}
Пусть все классы, которые вам нужны, реализуют этот интерфейс. Если вы знаете, какой класс он есть, вы можете просто использовать его как
SomeClass a = new SomeClass();
SomeClass clone = a.copy();
Или, если вы только знаете, что это копируемый:
Copyable<?> copy = x.copy();
Но в большинстве случаев лучше использовать существующее решение, подобное вышеизложенному.
(Edit: всегда лучший выбор не использовать javas-собственный клон-материал :))
Я думаю, вы можете сделать это, используя отражение,
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.
}