- 文档
- 知识库
- 教程
- OpenHarmony
【免费下载链接】CangjieCorpus
本仓库为仓颉编程语言语料库,聚焦 仓颉编程语言 核心知识体系,整合官方开发指南、API 文档、典型代码示例及语法规范等多维度资源,经结构化处理与专业标注,构建为支持 RAG(检索增强生成)技术 的高质量知识基座,适配智能编码助手、学习辅助工具等应用开发需求。 欢迎开发者基于本语料库构建仓颉语言智能应用,推动鸿蒙开发生态智能化升级!
ArrayList 是仓颉编程语言标准库std.collection包提供的可变长度动态数组容器,适合需要频繁增加和删除元素的场景。本文以官方指南 collection_arraylist.md 为主体,结合标准库 collection 包类 API 与仓库内可运行示例,系统讲解 ArrayList 的导入、构造、成员访问、增删改操作、切片以及容量管理策略。读完本文,你将掌握 ArrayList 的完整使用方法,并理解其底层扩容机制与性能取舍。
导入与类型声明
使用ArrayList类型需要先导入 collection 包:
import std.collection.*仓颉使用ArrayList<T>表示 ArrayList 类型,其中T表示 ArrayList 的元素类型,T可以是任意类型(包括类、结构体、枚举、基础类型等)。元素类型不相同的 ArrayList 属于不相同的类型,它们之间不可以互相赋值,以下写法是不合法的:
var a: ArrayList<Int64> = ... // ArrayList whose element type is Int64 var b: ArrayList<String> = ... // ArrayList whose element type is String b = a // Type mismatch,编译报错从 API 文档可以看到,ArrayList<T>实现了List<T>接口(List<T>又继承自ReadOnlyList<T>与Collection<T>),因此它既具备只读列表的get、[]、first、last等能力,也具备add、remove等修改能力,具体声明见 collection 包类 API 中的 ArrayList 章节。
与 Array 的定位差异:Array 是长度不变的定长数组,只支持修改元素、不支持增加和删除元素(参见 数组类型);而 ArrayList 既可以原地修改元素,也可以原地增加和删除元素,这是两者最本质的区别。
构造 ArrayList 的五种方式
仓颉中可以使用构造函数的方式构造一个指定的 ArrayList。官方指南给出了五种典型构造形式:
let a = ArrayList<String>() // Created an empty ArrayList whose element type is String let b = ArrayList<String>(100) // Created an ArrayList whose element type is String, and allocate a space of 100 let c = ArrayList<Int64>([0, 1, 2]) // Created an ArrayList whose element type is Int64, containing elements 0, 1, 2 let d = ArrayList<Int64>(c) // Use another Collection to initialize an ArrayList let e = ArrayList<String>(2, {x: Int64 => x.toString()}) // Created an ArrayList whose element type is String and size is 2. All elements are initialized by specified rule function结合标准库 API 文档,可以补充更多细节:
ArrayList<T>():构造一个空 ArrayList,初始容量为默认值16(见 init() 定义)。ArrayList<T>(capacity: Int64):构造初始容量为指定大小的 ArrayList。如果capacity小于 0,会抛出IllegalArgumentException。ArrayList<T>(size: Int64, initElement: (Int64) -> T):构造具有指定元素个数和初始化规则函数的 ArrayList,例如ArrayList<String>(2, {x: Int64 => x.toString()})会生成两个元素"0"、"1";size小于 0 时抛出IllegalArgumentException。ArrayList<T>(elements: Collection<T>):用另一个相同元素类型的 Collection 初始化,元素按集合迭代器返回的顺序排列,因此ArrayList<Int64>(c)会复制c的全部元素。ArrayList<T>.of(elements: Array<T>)(静态方法):从数组构造 ArrayList,例如ArrayList<Int64>.of([0, 1, 2])。
访问 ArrayList 成员
使用 for-in 遍历全部元素
ArrayList实现了Iterable接口(底层调用iterator()返回迭代器),因此可以直接使用 for-in 循环遍历所有元素:
import std.collection.* main() { let list = ArrayList<Int64>([0, 1, 2]) for (i in list) { println("The element is ${i}") } }编译并执行上面的代码,会输出:
The element is 0 The element is 1 The element is 2关于 for-in 与迭代器的等价展开(it.next()匹配Some/None),可参见 Iterable 和 Collections 一节。需要注意:collection 包的容器类都不支持并发修改,在 for-in 遍历过程中对容器进行增删修改会抛出ConcurrentModificationException(详见 collection 包异常说明)。
获取元素个数:size 属性
使用size属性可以获得 ArrayList 包含的元素个数:
import std.collection.* main() { let list = ArrayList<Int64>([0, 1, 2]) if (list.size == 0) { println("This is an empty arraylist") } else { println("The size of arraylist is ${list.size}") } }编译并执行上面的代码,会输出:
The size of arraylist is 3下标访问单个元素
访问指定位置的元素使用下标语法,下标的类型必须是Int64。非空 ArrayList 的第一个元素总是从位置 0 开始,可以访问 0 到size - 1的任意位置。使用负数或大于等于size的索引会触发运行时异常(IndexOutOfBoundsException):
let a = list[0] // a == 0 let b = list[1] // b == 1 let c = list[-1] // Runtime exceptions从源码结构看,下标访问由operator func [](index: Int64): T运算符重载实现,索引越界时抛出IndexOutOfBoundsException。另外,标准库还提供了get(index: Int64): ?T方法——与下标语法不同,get在索引越界时返回None而不是抛异常,适合需要安全读取的场景,仓库示例 sample_arraylist_get_set.md 展示了其配合getOrThrow()的用法:
var list = ArrayList<Int64>([97, 100]) // list: [97, 100] list[1] = 120 // 修改:list: [97, 120] var b = list.get(1) // 获取:b 为 ?Int64 print("b=${b.getOrThrow()}") // 输出 b=120使用 Range 切片
ArrayList 同样支持下标中传入Range<Int64>进行切片,切片返回的是一个全新的ArrayList对象,与原 ArrayList 无引用关系;range.step不等于 1 或范围无效时会抛出异常。相关语法细节与 Array 保持一致,详见 数组类型(Array 章节)。切片运算符的底层定义为operator func [](range: Range<Int64>): ArrayList<T>,另外也存在独立的slice(range: Range<Int64>): ArrayList<T>方法,仓库示例 sample_arraylist_remove_clear_slice.md 演示了切片用法:
let r: Range<Int64> = 1..=2 : 1 var sublist: ArrayList<Int64> = list.slice(r) // sublist: [2, 3]修改 ArrayList
下标修改元素
可以使用下标语法对某个位置的元素进行修改:
let list = ArrayList<Int64>([0, 1, 2]) list[0] = 3引用共享语义
ArrayList 是引用类型,作为表达式使用时不会拷贝副本,同一个 ArrayList 实例的所有引用都会共享同样的数据。因此对 ArrayList 元素的修改会影响到该实例的所有引用:
let list1 = ArrayList<Int64>([0, 1, 2]) let list2 = list1 list2[0] = 3 // list1 contains elements 3, 1, 2 // list2 contains elements 3, 1, 2若确实需要一份独立的副本,可以调用clone()方法获得浅拷贝(新 ArrayList 实例与原有对象互不影响,元素引用仍共享)。
末尾追加元素
使用add(element: T)将单个元素追加到末尾;使用add(all!: Collection<T>)一次性追加同元素类型 Collection(例如 Array)中的全部元素,元素按迭代器顺序追加:
import std.collection.* main() { let list = ArrayList<Int64>() list.add(0) // list contains element 0 list.add(1) // list contains elements 0, 1 let li = [2, 3] list.add(all: li) // list contains elements 0, 1, 2, 3 }仓库示例 sample_arraylist_add.md 给出了容量预分配与批量追加组合的完整可运行代码:
import std.collection.* main() { var list: ArrayList<Int64> = ArrayList<Int64>(10) // 创建一个容量为 10 的 ArrayList var arr: Array<Int64> = [1, 2, 3] list.add(all: arr) // list: [1, 2, 3] list[1] = 120 // list: [1, 120, 3] var b = list.get(2) print("b=${b.getOrThrow()},") // b=3 list.add(12, at: 1) // list: [1, 12, 120, 3] var c = list.get(2) print("c=${c.getOrThrow()},") // c=120 var arr1: Array<Int64> = [1,2,3] list.add(all: arr1, at: 1) // list: [1, 1, 2, 3, 12, 120, 3] var d = list.get(2) print("d=${d.getOrThrow()}") // d=2 return 0 }运行结果:
b=3,c=120,d=2指定位置插入元素
add(element: T, at!: Int64)将单个元素插入到指定索引;add(all!: Collection<T>, at!: Int64)从指定位置开始插入整个 Collection。该索引处的元素和后面的元素会被挪后以腾出空间,at超出范围时抛出IndexOutOfBoundsException:
let list = ArrayList<Int64>([0, 1, 2]) // list contains elements 0, 1, 2 list.add(4, at: 1) // list contains elements 0, 4, 1, 2删除元素
使用remove(at!: Int64)删除指定索引的元素,被删除元素之后的元素会前移以填充空间,返回值是被移除的元素:
let list = ArrayList<String>(["a", "b", "c", "d"]) // list contains the elements "a", "b", "c", "d" list.remove(at: 1) // Delete the element at subscript 1, now the list contains elements "a", "c", "d"标准库还提供remove(range: Range<Int64>)按范围批量删除、removeIf(predicate: (T) -> Bool)按条件删除(注意在 predicate 内增删改容器会抛出ConcurrentModificationException)、以及clear()清空全部元素。仓库示例 sample_arraylist_remove_clear_slice.md 综合演示了这些操作:
import std.collection.* main() { var list: ArrayList<Int64> = ArrayList<Int64>([97, 100, 99]) // 变长参数列表的构造语法糖 list.remove(at: 1) // list: [97, 99] var b = list.get(1) print("b=${b.getOrThrow()},") // b=99 list.clear() list.add(11) // list: [11] var arr: Array<Int64> = [1, 2, 3] list.add(all: arr, at: 0) // list: [1, 2, 3, 11] var g = list.get(0) print("g=${g.getOrThrow()},") // g=1 let r: Range<Int64> = 1..=2 : 1 var sublist: ArrayList<Int64> = list.slice(r) // sublist: [2, 3] var m = sublist.get(0) print("m=${m.getOrThrow()}") // m=2 return 0 }运行结果:
b=99,g=1,m=2增加 ArrayList 的大小:扩容机制与 reserve
每个 ArrayList 都需要特定数量的内存来保存其内容。当向 ArrayList 添加元素并且它开始超出其保留容量时,ArrayList 会分配更大的内存区域,并将其所有元素复制到新内存中。这种增长策略意味着触发重新分配内存的添加操作具有性能成本;但随着 ArrayList 的保留内存变大,这类重新分配发生的频率会越来越低。
从标准库 API 的reserve(additional: Int64)定义可以看到具体的扩容规则:当additional小于等于零时不发生扩容;当剩余容量大于等于additional时不发生扩容;当剩余容量小于additional时,取「原始容量的 1.5 倍向下取整」与「additional+ 已使用容量」两者中的较大值进行扩容。若扩容后总容量超过Int64.Max会抛出OverflowException。
如果预先知道大约需要添加多少个元素,可以在添加之前预备足够的内存以避免中间重新分配,从而提升性能表现:
import std.collection.* main() { let list = ArrayList<Int64>(100) // Allocate space at once for (i in 0..100) { list.add(i) // Does not trigger reallocation of space } list.reserve(100) // Prepare more space for (i in 0..100) { list.add(i) // Does not trigger reallocation of space } }此外,capacity属性可以随时查询 ArrayList 当前容量大小,便于评估后续添加操作是否会触发扩容。
其他常用能力与注意事项
- 判等与包含:
ArrayList<T>在T <: Equatable<T>时支持==/!=运算符(两个数组相等指对应位置元素分别相等),并可通过contains(element: T)判断是否包含指定元素。 - 转字符串与转数组:
toString()输出形如"[elem1, elem2, elem3]"的字符串;toArray()返回按正确顺序排列的Array<T>。 - 遍历与排序:
iterator()返回按顺序遍历的迭代器。注意sort、sortDescending、sortBy等成员排序方法已标记为 deprecated,官方建议改用 sort 包函数。 - 线程安全:collection 包提供的集合类型(包括 ArrayList)都不支持并发安全,多线程场景请使用 collection.concurrent 包。
结语
ArrayList 是仓颉语言中面向「频繁增删查改」场景的动态数组容器,其可变长度、引用共享语义、指定位置插入删除以及预分配容量等能力,使它比定长的 Array 更灵活。结合标准库 类 API 文档 与仓库内的 add、get/set、remove/clear/slice 三份可运行示例,读者可以快速将上述 API 应用到实际项目中。关于 ArrayList 与其他基础 Collection(Array、HashSet、HashMap)的选择依据,可进一步参考 基础 Collection 类型概述。
- 文档
- 知识库
- 教程
- OpenHarmony
【免费下载链接】CangjieCorpus
本仓库为仓颉编程语言语料库,聚焦 仓颉编程语言 核心知识体系,整合官方开发指南、API 文档、典型代码示例及语法规范等多维度资源,经结构化处理与专业标注,构建为支持 RAG(检索增强生成)技术 的高质量知识基座,适配智能编码助手、学习辅助工具等应用开发需求。 欢迎开发者基于本语料库构建仓颉语言智能应用,推动鸿蒙开发生态智能化升级!
相关推荐
仓颉编程语言 ArrayList 详解:动态数组的构造、访问、修改与扩容策略
仓颉编程语言 ArrayList 详解:动态数组的构造、访问、修改与扩容策略 ArrayList<T 是仓颉标准库 std.collection 包提供的动态数
文档编程语言仓颉语言 ArrayList 使用指南:可变动态数组的构造、遍历、增删改与扩容优化
仓颉语言 ArrayList 使用指南:可变动态数组的构造、遍历、增删改与扩容优化 ArrayList 是仓颉标准库 std.collection 中提供的有序
文档编程语言仓颉语言 HashMap 集合类型详解:从构造、遍历访问到增删改的完整实践
仓颉语言 HashMap 集合类型详解:从构造、遍历访问到增删改的完整实践 HashMap 是仓颉语言 std.collection 包中用于存储键值对映射关系
文档编程语言
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考