ArrayBuffer 和 Array 有什么区别?

24

我是scala/java的新手,我有些困惑,不知道这两者之间有什么区别。

通过阅读scala 文档,我了解到ArrayBuffer 的设计目的是可互动操作(追加,插入,前置等)。

1)它们之间的基本实现差异是什么?

2)它们之间是否存在性能差异?

4个回答

48

ArrayArrayBuffer都是可变的,这意味着您可以修改特定索引处的元素:a(i) = e

ArrayBuffer是可调整大小的,Array则不是。如果您向ArrayBuffer附加一个元素,它会变大。如果您尝试将一个元素附加到Array中,则会得到一个新的数组。因此,要有效地使用Array,必须事先知道其大小。

Array在JVM级别上实现,并且是唯一的非擦除通用类型。这意味着它们是存储对象序列的最有效方式 - 没有额外的内存开销,并且一些操作被实现为单个JVM操作码。

ArrayBuffer通过在内部拥有一个Array并在需要时分配一个新的来实现。附加通常很快,除非它达到限制并调整数组大小 - 但它以一种使总体效果可以忽略不计的方式进行,因此不用担心。预先添加是通过将所有元素移动到右侧并将新元素设置为第0个元素来实现的,因此速度较慢。在循环中附加n个元素是高效的(On)),但预先添加这些元素则不是(On²))。

Array对于内置值类型(除Unit之外)进行了专门化处理,因此Array[Int]ArrayBuffer[Int]更加优化 - 值不必被装箱,因此使用的内存和间接性较少。请注意,专门化仅在类型是单态时起作用 - Array[T]将始终被装箱。


问题:Karol中的boxed是什么意思?解释得非常好。 - human
@datmannz 在Scala中的装箱(Boxing)与Java基本相同,这里是关于Java的官方文档:https://docs.oracle.com/javase/tutorial/java/data/autoboxing.html - Karol S

4
另一个区别是,Array的元素在声明时创建,但除非您第一次为其分配值,否则不会创建Array Buffer的元素。
例如,您可以写Array1(0)=“Stackoverflow”但不能写ArrayBuffer1(0)=“Stackoverflow”用于第一次值分配。
(Array1 = Array变量&ArrayBuffer1 = ArrayBuffer变量)
因为我们知道,数组缓冲区是可调整大小的,所以当您第一次插入值时创建元素,然后您可以修改/重新分配它们的特定元素。

数组:

声明并将值分配给Int数组。
val favNums= new Array[Int](20)

for(i<-0 to 19){
favNums(i)=i*2
}
favNums.foreach(println)

ArrayBuffer:

声明并分配整数ArrayBuffer的值。

val favNumsArrayBuffer= new ArrayBuffer[Int]
    for(j<-0 to 19){
    favNumsArrayBuffer.insert(j, (j*2))
    //favNumsArrayBuffer++=Array(j*3)
      }
    favNumsArrayBuffer.foreach(println)

如果你在for循环的第一行包含favNumsArrayBuffer(j)=j*2,它将无法正常工作。但是如果你在循环的第二或第三行声明它,那么它就可以正常工作了。因为在第一行已经分配了值,现在你可以通过元素索引进行修改。
这个简单的一小时视频教程解释了很多。 https://youtu.be/DzFt0YkZo8M?t=2005

插入和删除操作不适用于数组,但适用于ArrayBuffer。 - Shiv
favNumsArrayBuffer.insert(5,0,1,2,3,4) - Shiv

3

如果数组长度固定,请使用Array,如果长度可变,请使用ArrayBuffer


为什么 :+= 可以在 Array 上工作?这个答案如何改进或补充了 @KarolS 的更详细的答案? - jwvh

1

另一个区别在于引用和值的相等性。

Array(1,2) == Array(1,2)              // res0: Boolean = false
ArrayBuffer(1, 2) == ArrayBuffer(1,2) // res1: Boolean = true

差异的原因在于== routes.equals 的转换,其中Array.equals 是使用Java的==实现的,它比较引用。
public boolean equals(Object obj) {
  return (this == obj);
}

ArrayBuffer.equals 比较 ArrayBuffer 中包含的元素时,使用 sameElements 方法。

  override def equals(o: scala.Any): Boolean = this.eq(o.asInstanceOf[AnyRef]) || (
    o match {
      case it: Seq[A] => (it eq this) || (it canEqual this) && sameElements(it)
      case _ => false
    }
  )

同样, contains 的行为有所不同

Array(Array(1,2)).contains(Array(1,2))                   // res0: Boolean = false
ArrayBuffer(ArrayBuffer(1,2)).contains(ArrayBuffer(1,2)) // res1: Boolean = true

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