用一个对象的克隆填充数组

3
什么是用快速简便的方法将Java数组填充为一个对象的克隆体?
例如,在此之后:
Rectangle[] rectangles = new Rectangle[N];
fillWithClones(rectangles, new Rectangle(1, 2, 3, 4));

rectangles数组将包含N个不同的Rectangle实例,这些实例使用相同的坐标进行初始化。

我意识到Java中Object.clone()的缺陷,但在这种情况下,我知道要复制的对象具有非抛出异常的公共clone()方法,但可能或可能没有公共拷贝构造函数。

我猜测库中肯定有一个方法可以做到这一点,但我认为它不是JDK、Commons-collections或者Guava中的方法。

4个回答

1

如果您在编译时没有特定类型可供使用,则必须通过反射调用clone方法。

private static <T> T cloneByReflection(T object) {
    try {
        return (T) object.getClass().getMethod("clone").invoke(object);
    } catch (Exception e) {
        return null;    // or whatever you want to do
    }
}

public static <T> void fillWithClones(T[] array, T template) {
    for (int i = 0; i < array.length; ++i)
        array[i] = cloneByReflection(template);
}

第二个方法签名应简化为 public static void fillWithClones(Object[] array, Object template) - user102008

0

对于矩形:

public void fillWithClones(Rectangle[] arr, Rectangle src) {
    for(int xa=0,len=arr.length; xa<len; xa++) { arr[xa]=(Rectangle)src.clone(); }
    }

对于未知类型,Object.clone 是受保护的。你只能通过反射访问该方法(当然,前提是目标类型定义了公共覆盖)。 - C. K. Young
@Chris:糟糕,Clonable 真是个烂摊子。我删掉了错误的无类型方法。 - Lawrence Dol

0
如果存在复制构造函数(并且您希望在存在时使用它),则可以执行以下操作:
(编辑:更新代码以使用数组而不是列表):
private static <T> void fillWithClones( T[] array, T object )
{
  try
  {
    @SuppressWarnings("unchecked")
    Class<T> clazz = (Class<T>)object.getClass();
    Constructor<T> c = clazz.getConstructor( object.getClass() );

    try
    {
      for ( int i = 0; i < array.length; i++ )
      {
        array[i] = (T)c.newInstance( object );
      }
    }
    catch ( Exception e )
    {
      // Handle exception or rethrow...
    }
  }
  catch ( NoSuchMethodException e )
  {
    // No copy constructor, try clone option...
  }
}

当然,有些异常处理可以整理一下。


一个构造函数 T(T) 不一定是拷贝构造函数(例如 JFrameJScrollPaneClassLoaderPropertiesThrowable)。 - finnw
@finnw:是的,很好的发现。我想说,到最后你需要知道一些关于你要复制的对象的信息,才能选择合适的解决方案。 - Ash
泛型在这里没有作用。只需执行 private static void fillWithClones( Object[] array, Object object ) 并将 T 更改为 ? - user102008

0

@Chris Jester-Young的答案给你提供了想要做的事情的步骤。

但是我建议这种类型的应用程序有些问题。

  • 为什么你的应用程序需要复制随机事物数组的深层副本?如果你不知道这些事物的类型,如何确定复制是必要的呢?

  • 当数组包含无法克隆的对象时,你的应用程序应该怎么做?你抛出异常吗?你在数组中放一个null,需要以后检查空值吗?

更好的设计是让您可能想要克隆的所有对象实现具有(公共)克隆方法的接口。这样,您就可以拥有静态类型的解决方案(没有动态类型异常!),并且可以避免调用clone反射的开销。


类型并非“随机”的。在每种情况下,类型都是已知的,但我更喜欢使用通用方法来使程序更小。其中一些类来自JDK,因此我无法为它们定义新接口。如果此方法遇到不可克隆的对象,则应抛出CloneNotSupportedException - finnw
@finnw - 第一个问题呢?你的应用程序为什么需要首先克隆对象? - Stephen C

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接