【scala原理系列】scala ArrayBuffer 原理示例方法源码分析

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 源码的分析总结:

  1. ArrayBuffer 继承了多个 trait 和类,包括 AbstractBufferBufferGenericTraversableTemplateBufferLikeIndexedSeqOptimizedBuilderResizableArrayCustomParallelizableSerializable

  2. ArrayBuffer 的主构造函数接受一个初始大小 initialSize 参数,用于指定内部数组的初始容量。

  3. ArrayBuffer 实现了 companion 方法,返回一个与之关联的伴生对象,类型为 GenericCompanion[ArrayBuffer]

  4. ArrayBuffer 实现了 += 方法,用于向序列追加单个元素。该方法会检查内部数组的容量是否足够,如果不够,则会自动扩容,并将新元素添加到数组末尾。

  5. ArrayBuffer 实现了 ++= 方法,用于向序列追加一个可遍历对象中的所有元素。如果可遍历对象是 scala.collection.IndexedSeqLike 类型的,则会直接将元素复制到内部数组中;否则,会调用父类的 ++= 方法实现。

  6. ArrayBuffer 还实现了 +=: 方法和 ++=: 方法,用于在序列的开头插入元素或可遍历对象中的所有元素。这些方法会先扩容内部数组,然后将现有元素向后移动,并在开头插入新元素。

  7. ArrayBuffer 实现了 insertAll 方法,用于在指定位置插入一个可遍历对象中的所有元素。该方法会先检查插入位置的合法性,然后根据可遍历对象的大小调整内部数组的容量,并将元素插入到指定位置。

  8. ArrayBuffer 实现了 remove 方法,用于删除指定位置的元素或一定数量的连续元素。该方法会先检查删除范围的合法性,然后将后续元素向前移动,覆盖被删除的元素。

  9. ArrayBuffer 还实现了其他方法,如 clear 方法用于清空序列、sizeHint 方法用于设置序列的预期长度、result 方法返回自身作为结果等。

  10. ArrayBuffer 还提供了一些辅助方法,如 stringPrefix 方法用于定义序列的字符串表示的前缀。

  11. 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]
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

BigDataMLApplication

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值