scala ArrayBuffer 源码分析
ArrayBuffer
是 Scala 中的一个可变序列(mutable sequence)类,使用数组作为内部表示。它提供了高效的操作方式,包括追加、更新和随机访问等。
原理
以下是对 ArrayBuffer
类的原理进行的解释:
ArrayBuffer
使用数组来存储序列的元素,这样可以实现常数时间的追加、更新和随机访问操作。- 在追加元素时,
ArrayBuffer
会检查内部数组的容量是否足够,如果不够,则会自动扩容。扩容的策略一般是创建一个更大的数组,并将原数组的元素复制到新数组中,然后将新元素添加到新数组中。 - 在更新元素时,
ArrayBuffer
可以直接通过索引访问数组,并修改对应位置的元素值。 ArrayBuffer
还支持插入、删除和清空操作,这些操作的性能取决于序列的大小。在插入和删除操作时,需要移动其他元素来保持序列的连续性。ArrayBuffer
还提供了一些方便的方法,如获取序列的长度、判断是否为空、遍历元素等。
示例
下面是一个简单示例,展示了如何使用 ArrayBuffer
类:
import scala.collection.mutable.ArrayBuffer
// 创建一个空的 ArrayBuffer
val buffer = new ArrayBuffer[Int]()
// 追加元素到 ArrayBuffer
buffer += 1
buffer += 2
buffer += 3
// 更新元素的值
buffer(0) = 10
// 遍历元素并打印输出
for (elem <- buffer) {
println(elem)
}
// 插入元素到指定位置
buffer.insert(1, 20)
// 删除指定位置的元素
buffer.remove(2)
// 清空 ArrayBuffer
buffer.clear()
在上述示例中,我们首先创建了一个空的 ArrayBuffer
对象。然后,我们使用 +=
操作符追加元素到序列中,并使用索引操作符 ()
更新元素的值。接下来,使用循环遍历元素并打印输出。然后,我们使用 insert
方法在指定位置插入元素,并使用 remove
方法删除指定位置的元素。最后,使用 clear
方法清空了 ArrayBuffer
。
通过使用 ArrayBuffer
,我们可以方便地进行动态大小的序列操作,包括追加、更新、插入和删除等。它是一种高效的数据结构,适用于需要频繁修改序列内容的场景。
方法总结
ArrayBuffer
是 Scala 中的一个可变序列类,它使用数组作为内部数据结构来存储元素。下面是对 ArrayBuffer
源码的分析总结:
-
ArrayBuffer
继承了多个 trait 和类,包括AbstractBuffer
、Buffer
、GenericTraversableTemplate
、BufferLike
、IndexedSeqOptimized
、Builder
、ResizableArray
、CustomParallelizable
和Serializable
。 -
ArrayBuffer
的主构造函数接受一个初始大小initialSize
参数,用于指定内部数组的初始容量。 -
ArrayBuffer
实现了companion
方法,返回一个与之关联的伴生对象,类型为GenericCompanion[ArrayBuffer]
。 -
ArrayBuffer
实现了+=
方法,用于向序列追加单个元素。该方法会检查内部数组的容量是否足够,如果不够,则会自动扩容,并将新元素添加到数组末尾。 -
ArrayBuffer
实现了++=
方法,用于向序列追加一个可遍历对象中的所有元素。如果可遍历对象是scala.collection.IndexedSeqLike
类型的,则会直接将元素复制到内部数组中;否则,会调用父类的++=
方法实现。 -
ArrayBuffer
还实现了+=:
方法和++=:
方法,用于在序列的开头插入元素或可遍历对象中的所有元素。这些方法会先扩容内部数组,然后将现有元素向后移动,并在开头插入新元素。 -
ArrayBuffer
实现了insertAll
方法,用于在指定位置插入一个可遍历对象中的所有元素。该方法会先检查插入位置的合法性,然后根据可遍历对象的大小调整内部数组的容量,并将元素插入到指定位置。 -
ArrayBuffer
实现了remove
方法,用于删除指定位置的元素或一定数量的连续元素。该方法会先检查删除范围的合法性,然后将后续元素向前移动,覆盖被删除的元素。 -
ArrayBuffer
还实现了其他方法,如clear
方法用于清空序列、sizeHint
方法用于设置序列的预期长度、result
方法返回自身作为结果等。 -
ArrayBuffer
还提供了一些辅助方法,如stringPrefix
方法用于定义序列的字符串表示的前缀。 -
ArrayBuffer
的伴生对象是ArrayBuffer
,它实现了SeqFactory[ArrayBuffer]
trait,并提供了一些静态方法和隐式转换。其中,canBuildFrom
方法用于创建CanBuildFrom
对象,用于确定返回集合类型的结果类;newBuilder
方法用于创建一个新的ArrayBuffer
实例。
综上所述,ArrayBuffer
是一个高效的可变序列类,内部使用数组来存储元素。它提供了一系列方法用于操作序列,包括追加、更新、插入和删除等。通过自动扩容和移动元素的方式,ArrayBuffer
能够以常数时间进行追加、更新和随机访问操作,并且在插入和删除操作时具有较高的性能。
中文源码
/**
* 使用数组来表示内部组装序列的`Buffer`类的实现。附加、更新和随机访问的时间复杂度为常数(平摊时间)。前置和删除的时间复杂度与缓冲区大小成线性关系。
*
* @author Matthias Zenger
* @author Martin Odersky
* @version 2.8
* @since 1
* @see [[http://docs.scala-lang.org/overviews/collections/concrete-mutable-collection-classes.html#array_buffers "Scala's Collection Library overview"]]
* 关于`Array Buffers`的更多信息,请参见相关文档
*
* @tparam A 数组缓冲区元素的类型。
*
* @define Coll `mutable.ArrayBuffer`
* @define coll 数组缓冲区
* @define thatinfo 返回集合的类。在标准库配置中,`That`始终是`ArrayBuffer[B]`,因为在`ArrayBuffer`对象中定义了一个类型为`CanBuildFrom[ArrayBuffer, B, ArrayBuffer[B]]`的隐式值。
* @define bfinfo 类型为`CanBuildFrom`的隐式值,用于确定当前表示类型`Repr`和新元素类型`B`的结果类`That`。这通常是在`ArrayBuffer`对象中定义的`canBuildFrom`值。
* @define orderDependent
* @define orderDependentFold
* @define mayNotTerminateInf
* @define willNotTerminateInf
*/
@SerialVersionUID(1529165946227428979L)
class ArrayBuffer[A](override protected val initialSize: Int)
extends AbstractBuffer[A]
with Buffer[A]
with GenericTraversableTemplate[A, ArrayBuffer]
with BufferLike[A, ArrayBuffer[A]]
with IndexedSeqOptimized[A, ArrayBuffer[A]]
with Builder[A, ArrayBuffer[A]]
with ResizableArray[A]
with CustomParallelizable[A, ParArray[A]]
with Serializable {
override def companion: GenericCompanion[ArrayBuffer] = ArrayBuffer
import scala.collection.Traversable
def this() = this(16)
/**
* 清空缓冲区。
*/
def clear() { reduceToSize(0) }
/**
* 设置缓冲区大小的提示。
*
* @param len 缓冲区的预期大小。
*/
override def sizeHint(len: Int) {
if (len > size && len >= 1) {
val newarray = new Array[AnyRef](len)
scala.compat.Platform.arraycopy(array, 0, newarray, 0, size0)
array = newarray
}
}
/**
* 并行处理数组缓冲区。
*
* @return 一个`ParArray[A]`实例,表示并行处理的数组缓冲区。
*/
override def par = ParArray.handoff[A](array.asInstanceOf[Array[A]], size)
/**
* 在缓冲区末尾添加一个元素,并返回缓冲区的引用。平摊时间复杂度为常数。
*
* @param elem 要追加的元素。
* @return 更新后的缓冲区。
*/
def +=(elem: A): this.type = {
ensureSize(size0 + 1)
array(size0) = elem.asInstanceOf[AnyRef]
size0 += 1
this
}
/**
* 在缓冲区末尾追加一个可遍历对象中提供的多个元素,并返回缓冲区的引用。
*
* @param xs 可遍历对象。
* @return 更新后的缓冲区。
*/
override def ++=(xs: TraversableOnce[A]): this.type = xs match {
case v: scala.collection.IndexedSeqLike[_, _] =>
val n = v.length
ensureSize(size0 + n)
v.copyToArray(array.asInstanceOf[scala.Array[Any]], size0, n)
size0 += n
this
case _ =>
super.++=(xs)
}
/**
* 在缓冲区开头添加一个单个元素,并返回缓冲区的标识。时间复杂度与缓冲区大小成线性关系。
*
* @param elem 要添加的元素。
* @return 更新后的缓冲区。
*/
def +=:(elem: A): this.type = {
ensureSize(size0 + 1)
copy(0, 1, size0)
array(0) = elem.asInstanceOf[AnyRef]
size0 += 1
this
}
/**
* 在缓冲区开头添加由遍历对象提供的多个元素,并返回缓冲区的标识。
*
* @param xs 遍历对象。
* @return 更新后的缓冲区。
*/
override def ++=:(xs: TraversableOnce[A]): this.type = { insertAll(0, xs.toTraversable); this }
/**
* 在索引`n`处插入新元素。与`update`方法相对,此方法不会替换一个元素为新元素,而是在索引`n`处插入一个新元素。
*
* @param n 要插入新元素的索引位置。
* @param seq 提供要插入的所有元素的遍历对象。
* @throws IndexOutOfBoundsException 如果`n`超出范围。
*/
def insertAll(n: Int, seq: Traversable[A]) {
if (n < 0 || n > size0) throw new IndexOutOfBoundsException(n.toString)
val len = seq.size
val newSize = size0 + len
ensureSize(newSize)
copy(n, n + len, size0 - n)
seq.copyToArray(array.asInstanceOf[Array[Any]], n)
size0 = newSize
}
/**
* 删除给定索引位置上的元素。时间复杂度与缓冲区大小成线性关系。
*
* @param n 引用要删除的第一个元素的索引。
* @param count 要删除的元素数量。
* @throws IndexOutOfBoundsException 如果`n`超出范围。
*/
override def remove(n: Int, count: Int) {
require(count >= 0, "删除负数个元素")
if (n < 0 || n > size0 - count) throw new IndexOutOfBoundsException(n.toString)
copy(n + count, n, size0 - (n + count))
reduceToSize(size0 - count)
}
/**
* 删除给定索引位置上的元素。
*
* @param n 引用要删除的元素的索引。
* @return 原先在位置`n`的元素。
*/
def remove(n: Int): A = {
val result = apply(n)
remove(n, 1)
result
}
def result: ArrayBuffer[A] = this
/** 定义字符串表示形式的前缀。
*/
override def stringPrefix: String = "ArrayBuffer"
/**
* `ArrayBuffer`类的工厂对象。
*
* $factoryInfo
* @define coll 数组缓冲区
* @define Coll `ArrayBuffer`
*/
object ArrayBuffer extends SeqFactory[ArrayBuffer] {
/** $genericCanBuildFromInfo */
implicit def canBuildFrom[A]: CanBuildFrom[Coll, A, ArrayBuffer[A]] = ReusableCBF.asInstanceOf[GenericCanBuildFrom[A]]
def newBuilder[A]: Builder[A, ArrayBuffer[A]] = new ArrayBuffer[A]
}