通用阵列复制的问题

时间:2011-03-20 23:01:40

标签: java generics classcastexception

目标


我正在创建一个Java类,它将增强对数组的可用性,例如addremovecontains方法。我认为最好的解决方案是创建一个具有类型参数ArrayPP的类(称为T)。这样,用户可以使用相同类型的数组尽可能轻松地与ArrayPP对象进行交互。

问题


我很快发现像add这样的方法需要创建一个单独的数组,并最终将目标数组tT数组更改为一个数组Object秒。正如你可能猜到的那样,这完全破坏了可用性,当我尝试做类似

的事情时
File[] f = new File[0];
ArrayPP<File> appF = new ArrayPP(f);
appF.add(saveFile);
f = appF.toArray();

程序抛出

Exception in thread "main" java.lang.ClassCastException: [Ljava.lang.Object; cannot be cast to [Ljava.io.File;

因为add方法必须将数组更改为Object的数组,因为Java编译器不允许您创建通用数组(T[] t = new T[0];是坏的,但是T[] t = (T[]) new Object[0];没问题。我从逐行调试中得知,上面的代码将数组t保留为File的数组,直到add方法的第4行被调用。 有没有人有一个解决方案可以让数组t成为T的数组,而不是Object的数组?

示例代码


以下是我班级的一个非常淡化的版本。

public class ArrayPP<T>
{
  T[] t;

  /**
   * Creates a new Array++ to manage the given array.
   * <h3>Analogy:</h3>
   * <tt>ArrayPP&lt;String&gt; s = new ArrayPP(args);</tt><br/>
   * is analogous to<br/>
   * <tt>String s[] = args;</tt>
   * @param array The array to be managed
   */
  public ArrayPP(T[] array)
  {
    t = array;
  }

  /**
   * Appends a value to the end of the array
   * @param val the value to be appended
   * @return the resulting array.
   */
  public ArrayPP add(T val)
  {
    T[] temp = (T[]) new Object[t.length + 1];
    System.arraycopy(t, 0, temp, 0, t.length);
    temp[temp.length - 1] = val;
    t = (T[])temp;
    return this;
  }

  /**
   * Returns the array at the core of this wrapper
   * @return the array at the core of this wrapper
   */
  public T[] toArray()
  {
    return t;
  }
}

可能的解决方案?


在查看有关通用数组的其他问题之后,我想我有一个解决方案:

而不是

  /**
   * Appends a value to the end of the array
   * @param val the value to be appended
   * @return the resulting array.
   */
  public ArrayPP add(T val)
  {
    T[] temp = (T[]) new Object[t.length + 1];
    System.arraycopy(t, 0, temp, 0, t.length);
    temp[temp.length - 1] = val;
    t = (T[])temp;
    return this;
  }

这会有用吗?

  /**
   * Appends a value to the end of the array
   * @param val the value to be appended
   * @return the resulting array.
   */
  public ArrayPP<T> add(T val)
  {
    t = java.util.Arrays.copyOf(t, t.length + 1);
    t[t.length - 1] = val;
    return this;
  }

3 个答案:

答案 0 :(得分:2)

原则上,您无法轻松创建泛型类型(或类型变量)的数组。

如果你有一个类对象,你可以使用反射,或者如果你有一个示例数组,java.util.Arrays类中的方法可以创建一个(更长/更短)的副本。但无论如何它都不优雅。

ArrayList类在内部只使用Object[]来存储其元素,并仅在get / set / add / toArray上进行转换。 你的班级会比ArrayList做得更好吗?


编辑:

我建议简单地委托给ArraysList,或者像ArrayList那样执行,在内部使用Object[],并在必要时转换输出。

如果你真的想在内部拥有一个正确类型的数组,那么它是可能的 - 但正如我所说的那样它会变得难看。

add方法仍然是最简单的方法:

  /**
   * Appends a value to the end of the array
   * @param val the value to be appended
   * @return the resulting array.
   */
  public ArrayPP add(T val)
  {
     T[] temp = Arrays.copyOf(t, t.length+1);
     temp[t.length] = val;
     t = temp;
     return this;
  }

如果要在中间添加或删除,则必须将其与arraycopy相结合。

答案 1 :(得分:1)

是否有某些原因使内置List<T>类无法满足您的需求?如:

String[] theArray = {"a", "b", "c"};
List<String> theList = Arrays.asList(theArray);

答案 2 :(得分:0)

public ArrayPP(T[] array)
    componentClass = array.getClass().getComponentClass();

T[] newArray(int length)
    return Array.newInstance(componentClass, length)