【问题标题】:Fill an array with clones of a single object用单个对象的克隆填充数组
【发布时间】:2011-01-19 00:45:37
【问题描述】:

用单个对象的克隆填充 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 中。

【问题讨论】:

    标签: java arrays collections clone


    【解决方案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)
    【解决方案2】:

    @Chris Jester-Young 的回答为您提供了做自己想做的事情的秘诀。

    但我建议做这种事情的应用程序存在一些相当错误的地方。

    • 为什么您的应用程序需要制作随机事物数组的深层副本?如果你不知道东西的类型,你怎么知道复制是必要的?

    • 当数组包含不可克隆对象时,您的应用程序应该做什么?你抛出异常吗?您是否将null 放入数组中,需要稍后进行空值检查?

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

    【讨论】:

    • 类型不是“随机的”。在每种情况下,类型都是已知的,但我更喜欢通用方法来保持程序更小。有些类来自 JDK,因此我无法为它们定义新接口。如果这个方法遇到一个不可克隆的对象,它应该抛出一个CloneNotSupportedException
    • @finnw - 第一个子弹呢?为什么您的应用程序首先需要克隆对象?
    【解决方案3】:

    如果复制构造函数可能存在(如果存在,你想使用它),你可以这样做:

    (编辑:更新代码以使用数组而不是列表):

    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:是的,很好。我想在一天结束时,您需要了解关于您要复制的对象的一些信息,才能选择合适的解决方案。
    • 泛型在这里不起作用。只需执行private static void fillWithClones( Object[] array, Object object ) 并将T 更改为?
    【解决方案4】:

    对于矩形:

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

    【讨论】:

    • 对于未知类型,Object.clone 受到保护。您只能通过反射访问该方法(当然,只有当目标类型定义了公共覆盖时)。
    • @Chris:废话,Clonable 是个多么糟糕的事情。我删除了不正确的无类型方法。
    猜你喜欢
    • 1970-01-01
    • 2021-11-14
    • 1970-01-01
    • 1970-01-01
    • 2021-12-28
    • 2021-01-07
    • 2018-05-26
    • 1970-01-01
    • 2017-02-22
    相关资源
    最近更新 更多