我看到了这样的代码:
public int[][] test() {
Queue<Integer> queue = new PriorityQueue<>();
//Do Something
return queue.toArray(new int[0][0])
}
我很好奇最后一行,为什么这里允许int[0][0]
? queue.toArray
方法的参数不应该是Array恢复到的内存吗?
答案 0 :(得分:2)
toArray
的文档在这里:
https://docs.oracle.com/javase/7/docs/api/java/util/PriorityQueue.html#toArray(T[])
toArray
的签名是<T> T[] toArray(T[] a)
。
因此,编译器推断T = int[]
。
请注意,集合的类型参数是E
,而不是T
。
无论代码打算做什么,很可能会失败,因为文档说:
抛出:ArrayStoreException-如果指定的运行时类型 数组不是此元素中每个元素的运行时类型的超类型 集合
int[]
不是Integer
的超类型。
答案 1 :(得分:2)
queue.toArray方法的参数不应该是Array恢复到的内存吗?
不一定。
发生的事情是,toArray
方法计算出容纳集合内容所需的大小数组。如果提供的数组足够大,则将在其中写入内容。否则,将分配并使用一个新数组。在后一种情况下,参数数组的实际类型确定分配的数组的类型。
如@ReputationFarmer所述,在这种情况下,queue.toArray(new int[0][0])
可能会给出运行时异常(ArrayStoreException
)。呼叫应该是 queue.toArray(new Integer[0])
。
之所以不会产生编译错误,是因为此toArray
方法的类型签名为<T> T[] toArray(T[] a)
,它允许将 any 数组类型作为论点。
那么...为什么他们用这种方式定义toArray
?
答案是Java的历史:
在toArray
API中指定了Collection
方法,该API已在Java 1.2中添加到Java。
从Java 1.2到Java 1.4.2,此方法的签名为:
public Object[] toArray(Object[] a)
换句话说,您可以传递任何引用类型的数组,编译器会接受它。
他们在Java 5中引入了泛型,并重新定义了toArray
方法以使其具有当前签名。
我怀疑他们没有重新定义toArray
签名的原因是:
<T extends E> T[] toArray(T[] a)
对于某些在较早版本中有效的Java代码,它将中断(产生编译错误)。