Scala中的集合和toArray

时间:2013-10-03 02:41:36

标签: java scala

Java代码:

Collection<MethodInfo> items = getItems();
MethodInfo[] itemsArray = items.toArray(new MethodInfo[items.size()]);

我想知道,Scala中的等效代码是什么?

val items: Seq[MethodInfo] = getItems
val itemsArray: Array[MethodInfo]  = ???

2 个答案:

答案 0 :(得分:7)

正如@SpiderPig在他的评论中指出的那样,你可以简单地调用items.toArray将序列转换为数组。我想你可能会因为你必须用Java提供一个目标数组而感到困惑,但在Scala中你只需要调用toArray而没有参数。

您必须使用Java提供数组的原因与type erasure有关。 Java编译器不知道在编译时要创建什么类型的数组,并且由于Java数组不是通用的,因此需要具体类型才能实例化。

toArray的Java实现使用一种技巧来解决这个限制。通过传入所需类型的数组,JVM可以使用 数组上的反射来实例化数组,以创建正确类型的新数组。 (您实际上可以将0元素数组传递给toArray方法,它将分配一个正确大小的数组。toArray方法实际上将此工作委托给Arrays.copyOf,然后使用implementation for toArray用于创建副本的反射。)

Scala采用了不同的方法。与Java编译器(默认参数,隐式转换,隐式参数等)相比,Scala编译器在幕后做了更多工作。如果你看一下{{3}}:

,你可以看出有一些编译器魔法在起作用
def toArray[B >: A : ClassTag]: Array[B] = {
  if (isTraversableAgain) {
    val result = new Array[B](size)
    copyToArray(result, 0)
    result
  }
  else toBuffer.toArray
}

泛型类型中的ClassTag要求编译器提供类信息。这允许JVM为最终结果实例化正确类型和大小的数组。这意味着您不必提供数组,因为Scala库可以为您创建一个正确的类型和大小。

答案 1 :(得分:2)

Java中存在Collection#toArray(T[] a)的唯一原因是类型擦除。在运行时,Java不知道T是什么类型,因此无法创建类型为T[]的数组。由于您必须自己创建一个正确类型的数组,因此最好分配一个正确的大小以避免浪费空间或让Java分配另一个。

如果使用Collection#toArray()代替(不传递数组),Java将自动分配一个正确大小的数组,但由于没有类型信息,它将为Object[]

Scala的toArray方法有点先进:

def toArray[B >: A](implicit arg0: ClassTag[B]): Array[B]

基本上,它使用隐式参数来提供运行时类型信息,因此可以自动实例化正确类型的数组。您可以使用@ SpiderPig的代码而无需自己创建阵列,也不必担心大小。