我只是在查看List接口中定义的方法:<T> T[] toArray(T[] a) ,我有一个问题。为什么是通用的?因此,方法不是完全类型安全的。以下代码片段可编译但会导致ArrayStoreException:
<T> T[] toArray(T[] a)
ArrayStoreException
List<Integer> list = new ArrayList<Integer>(); list.add(1); list.add(2); String[] stringArray = list.toArray(new String[]{});
在我看来,如果toArray不是通用的并且采用List类型参数,那会更好。
我已经写了玩具示例,没有通用就可以了:
package test; import java.util.Arrays; public class TestGenerics<E> { private Object[] elementData = new Object[10]; private int size = 0; public void add(E e) { elementData[size++] = e; } @SuppressWarnings("unchecked") //I took this code from ArrayList but it is not generic public E[] toArray(E[] a) { if (a.length < size) // Make a new array of a's runtime type, but my contents: return (E[]) Arrays.copyOf(elementData, size, a.getClass()); System.arraycopy(elementData, 0, a, 0, size); if (a.length > size) a[size] = null; return a; } public static void main(String[] args) { TestGenerics<Integer> list = new TestGenerics<Integer>(); list.add(1); list.add(2); list.add(3); //You don't have to do any casting Integer[] n = new Integer[10]; n = list.toArray(n); } }
有什么理由可以这样声明?
从javadocs:
与toArray()方法一样,此方法充当基于数组的API和基于集合的API之间的桥梁。此外,此方法允许对输出数组的运行时类型进行精确控制,并且在某些情况下可以用于节省分配成本。
这意味着程序员可以控制它应该是哪种类型的数组。
例如,对于您的ArrayList<Integer>而不是Integer[]数组,您可能想要一个Number[]或Object[]数组。
ArrayList<Integer>
Integer[]
Number[]
Object[]
此外,该方法还会检查传入的数组。如果传入的数组具有足够的空间容纳所有元素,则该toArray方法将重用该数组。这表示:
toArray
Integer[] myArray = new Integer[myList.size()]; myList.toArray(myArray);
要么
Integer[] myArray = myList.toArray(new Integer[myList.size()]);
与…具有相同的效果
Integer[] myArray = myList.toArray(new Integer[0]);
注意,在较旧的Java版本中,后一个操作使用反射来检查数组类型,然后动态构造正确类型的数组。首先,通过传递大小正确的数组,不必在toArray方法内部使用反射来分配新的数组。情况不再如此,并且两个版本可以互换使用。