Java继承数组构造和协变返回



(标题听起来有点花哨,但我找不到匹配的,所以我们希望它是描述性的。)

我有一段工作代码,如下所示:

@SuppressWarnings("unchecked")
public static Copyable[] copyOf(Copyable[] objects, Class type) {
    Copyable[] copies = Arrays.copyOf(objects, objects.length, type);
    for( int i=0; i < copies.length; ++i ) {
        if( objects[i] == null )
            throw new IllegalArgumentException("Copyable[] contains null reference", new NullPointerException());
        copies[i] = objects[i].copy();
    }
    return copies;
}

不像我想的那么漂亮,因为我必须传入数组类,但它可以做我想做的事情:分配一个Copyable实现者的新数组,并使用实现的方法填充它。

我遇到的问题是,这是由GWT编译的,它的JRE仿真库禁止正确的Java,它没有实现。我需要在不调用Arrays.copyOf()的情况下做到这一点,并且希望没有反射。

注意:我正在使用clone()版本,但也不想依赖clone()。我觉得一定有一个更干净的解决方案。

这个怎么样:

public static Copyable[] copyOf(Copyable[] objects) {
    Copyable[] copies = new Copyable[objects.length];
    for( int i=0; i < copies.length; ++i ) {
        if( objects[i] == null )
            throw new IllegalArgumentException("Copyable[] contains null reference", new NullPointerException());
        copies[i] = objects[i].copy();
    }
    return copies;
}

在复制元素本身之前,不需要将objects数组实际复制到copies中。

编辑

如果你的Copyable对象是可序列化的,你可以只序列化,然后反序列化数组来创建一个副本。在gwt-test-utils中有一个实用程序函数DeepCopy.java,它可以完全满足您的需求。

你为什么不能这样做:Copyable[] copies = new Copyable[objects.length];吗?这一行分配数组,然后您已经用您包含的for循环填充它。

可能使用泛型:

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

import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.List;
public class Test {
  static class My implements Copyable<My> {
    int x;
    public My copy() {
      My my = new My();
      my.x = this.x;
      return my;
    }
  }
  @SuppressWarnings("unchecked")
  public static <T extends Copyable<T>> T[] copyOf(T[] objects, Class<T> type) {
    List<T> copies = new ArrayList<T>();
    for (int i = 0; i < objects.length; ++i) {
      if (objects[i] == null) throw new IllegalArgumentException("Copyable[] contains null reference",
          new NullPointerException());
      copies.add((T) objects[i].copy());
    }
    T typeVar = null;
    try {
      typeVar = (T) Class.forName(type.getName()).newInstance();
    } catch (InstantiationException e) {
      e.printStackTrace();
    } catch (IllegalAccessException e) {
      e.printStackTrace();
    } catch (ClassNotFoundException e) {
      e.printStackTrace();
    }
    Object t = Array.newInstance(typeVar.getClass(),0);
    return copies.toArray((T[])t); 
  }
  public static void main(String[] args) {
    My[] stuff = new My[1];
    My elem = new My();
    elem.x = 1;
    stuff[0] = elem;
    My[] copies = copyOf(stuff, My.class);
    System.out.println(copies[0].x);
  }
}

基于GriffeyDog的回答和我最近对泛型的一些乐趣,这里是一个没有Class对象的解决方案,直接在数组上工作:

@SuppressWarnings("unchecked")
public static <T extends Copyable> T[] copyOf(T[] objects) {
    T[] copies = (T[]) new Object[objects.length];
    for (int i = 0; i < copies.length; ++i) {
        if (objects[i] == null)
            throw new IllegalArgumentException(/*...*/);
        copies[i] = (T) objects[i].copy();
    }
    return copies;
}

您可以对数组本身使用clone(),然后对每个对象使用copy():

@SuppressWarnings("unchecked")
public static Copyable[] copyOf(Copyable[] objects) {
    Copyable[] copies = (Copyable[]) objects.clone();
    for( int i=0; i < copies.length; ++i ) {
        if( objects[i] == null )
            throw etc;
        copies[i] = objects[i].copy();
    }
    return copies;
}

每个数组都实现了clone()方法,该方法返回数组的浅拷贝。所以我认为它足够干净,可以满足你的需要。

注意,这样,您也不需要参数Class type

最新更新