如何创建一个新的AnyType[]数组?

4

在这种情况下,哪种方法是最佳实践?我想要一个与原始数组类型和长度相同但未初始化的数组。

public static <AnyType extends Comparable<? super AnyType>> void someFunction(AnyType[] someArray) {

    AnyType[] anotherArray = (AnyType[]) new Comparable[someArray.length];
     ...or...
    AnyType[] anotherArray = (AnyType[]) new Object[someArray.length];

    ...some other code...
}

谢谢,CB

为什么这被标记为“初学者”? - Rosdi Kasim
3个回答

7
AnyType[] anotherArray = (AnyType[])java.lang.reflect.Array.newInstance(
      someArray.getClass().getComponentType(), someArray.length);

3
应该指出的是,这将创建一个基础类型与输入数组的基础类型相同的数组。这不一定与编译器将推断出的通用类型参数相同。 - Stephen C
同时请注意,输入的“someArray”也是如此。创建的“anotherArray”可以像“someArray”一样安全地存储“AnyType”的实例。因此,此代码不会增加任何之前不存在的限制。 - Dimitris Andreou

5

数组和泛型并不是很搭配。这是因为数组是协变的,而泛型不是。让我举个例子:

public static void main(String args[]) {
  foo(new Float[1]);
}

public static void foo(Number[] n) {
  n[0] = 3;
}

这段代码可以编译,但会导致 ArrayStoreException 异常。

因此,在重建该数组时可能不是 AnyType 数组,而可能是 AnyType 的子类数组。当然,你可以使用 someArray.getClass() 和反射创建数组。

总体来说,你应该优先使用 List 而不是数组,因为 List 没有相同的问题。将代码更改为:

public static void main(String args[]) {
  foo(new ArrayList<Float>());
}

public static void foo(List<Number> list) {
  list.add(3);
}

而且代码无法编译,这是一个更好的结果。


5

一个很好的参考是查看 <T> T[] Collection.toArray(T[]) 是如何被 AbstractCollection 实现的:

public <T> T[] toArray(T[] a) {
    // Estimate size of array; be prepared to see more or fewer elements
    int size = size();
    T[] r = a.length >= size ? a :
              (T[])java.lang.reflect.Array
              .newInstance(a.getClass().getComponentType(), size);
    //...

所以这个技术使用了:

如果您绝对必须创建一个“通用”数组,则通过传递instanceof T[]并使用反射实例化另一个数组是Java集合框架所示的方式。

然而,您也必须质疑自己是否真的需要这样的功能。

来自Effective Java第二版: 条款25: 首选列表而不是数组:

总的来说,数组和泛型有非常不同的类型规则。数组是协变和具体化的,泛型是不变和擦除的。因此,数组提供了运行时类型安全性,但不提供编译时类型安全性,泛型则相反。一般来说,数组和泛型混合使用效果不佳。如果你发现自己在混合使用它们并收到编译时错误和警告,则应该首先用列表替换数组。

为了更全面地处理这个主题,您应该阅读整个条款。


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