【问题标题】:Java Deep Clone - Clone each element in ArrayList if Cloneable, regardless of typeJava Deep Clone - 如果可克隆,则克隆 ArrayList 中的每个元素,无论类型如何
【发布时间】:2014-03-12 17:59:11
【问题描述】:

我有一个 ArrayList a,它可以包含任何类型的对象。然后我需要遍历 ArrayList 的元素。如果元素实现了 Cloneable,我需要克隆该元素(意思是复制它并在内存中给它自己的位置)并将克隆的元素添加到 ArrayList b。问题在于铸造。我需要转换为正确的对象类型,然后调用 clone()。 (因为 Object 中的 clone() 是受保护的。)

在下面的代码中,我已经设法用一堆 if 语句来做到这一点。在每个元素上,我说 if Cloneable,然后嵌套在那个 if 语句中,我有更多的 if 语句,检查正确类型的实例。当程序找到正确的类型时,它会强制转换和克隆。所有这些代码都有效,但我想要一种在没有这些 if 语句的情况下进行强制转换然后 clone() 的方法,因为可能有一些我还不知道的类。有没有办法做到这一点? (我可以使用 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。

感谢您提供的任何帮助。

【问题讨论】:

  • 您是否正在尝试为实现您的深度克隆的 any 类解决这个问题?一般来说,以这种方式使用 instanceof 往往会产生代码异味。当新班级出现后会发生什么?您应该重新考虑整体设计问题。 javapractices.com/topic/TopicAction.do?Id=31

标签: java arraylist casting clone


【解决方案1】:

我认为你可以使用反射来做到这一点,

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.
}

【讨论】:

  • 抱歉,这不起作用。我收到以下错误:找不到符号符号:方法克隆()位置:接口 java.lang.Cloneable b.add(c.clone());也许是因为 clone() 在 Object 而不是 Cloneable 中? (可克隆为空)
  • 每一个Cloneable也是Object类型的,而且Object版本的clone也是不可见的。
  • @user1567060 编辑使用反射。
  • 如果你不需要,我建议不要使用反射。这真的很容易出错,你可以找到更简单的方法来解决这个问题。
  • 看来你的反思想法奏效了。我考虑过反思,但并没有以这种方式思考。我相信你对 Cloneable 扩展对象(因为我被告知所有对象都扩展对象)但 c.clone() 仍然没有工作。不过,看起来这个想法会奏效。感谢您的帮助,当我将解决方案实施到实际程序中时会通知您。 (可能今天晚些时候。)
【解决方案2】:

Java 中的整个克隆机制基本上都被打破了。 参见例如http://www.artima.com/intv/issues3.html

您可以使用具有所有功能的库(http://code.google.com/p/cloning/ -(Deep clone utility recomendation 归功于 Cojones)或创建自己的界面,例如

public interface Copyable<T> {
 T copy();
}

让您需要的所有类都实现该接口。如果你知道它是哪个类,你可以正常使用它

SomeClass a = new SomeClass();
SomeClass clone = a.copy();

或者如果你只知道它是可复制的:

Copyable<?> copy = x.copy();

但在大多数情况下,最好使用现有解决方案,例如上面的库。

(编辑:不使用 javas 自己的克隆东西总是最好的选择:))

【讨论】:

  • 我会尽快查看图书馆。谢谢!
猜你喜欢
  • 1970-01-01
  • 2010-10-17
  • 1970-01-01
  • 2013-01-26
  • 2017-06-05
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多