前言
在 Kotlin 里,数组和列表都是用于存储多个元素的数据结构,不过它们在特性和使用场景上存在差异。
介绍
Array(数组)
本质:Kotlin 的 Array
是底层数组的直接包装,与 Java 数组一一对应(如 IntArray
对应 Java 的 int[]
,Array<Int>
对应 Integer[]
)。
特性:
- 长度固定:创建时必须指定大小,且不可动态扩容 / 缩容。
- 可修改元素:通过索引
[]
可以修改元素(array[0] = 1
),但不能改变数组长度。 - 支持基本类型优化:如
IntArray
、DoubleArray
等避免了装箱拆箱,性能更好。
适用场景:需要固定长度的连续内存存储,或与 Java 数组交互时。
示例:
1 | val array = arrayOf(1, 2, 3) // 长度为3的Array<Int> |
Collection
Collection 是一个接口,它代表一组元素,但它本身并没有直接提供取值的方法。
这是因为 Collection
是一个通用的抽象概念,它只定义了集合的基本操作,例如检查集合的大小、判断元素是否存在等。
不过,Collection 有两个重要的子接口 List
和 Set
,它们提供了不同的取值方式。
1 | public interface Collection<out E> : Iterable<E> { |
List(只读列表接口)
本质:Kotlin 标准库中的只读列表接口,继承自 Collection
,定义了列表的查询操作。
特性:
- 不可修改:仅支持查询(
get(index)
、size
、contains()
等),无add
、remove
等修改方法。 - 长度可变(间接):若底层是可变列表(如
ArrayList
),通过原可变列表修改时,List
视图会同步变化(但不能直接通过List
接口修改)。 - 无固定实现:
List
是接口,具体实现由ArrayList
、LinkedList
等提供。
适用场景:仅需读取数据,或作为不可变数据传递(避免外部修改)。
示例:
1 | val list: List<Int> = listOf(1, 2, 3) |
修改
1 | val selectIndexList: List<Int> = listOf(1, 2, 3) |
MutableList(可变列表接口)
本质:继承自 List
的子接口,新增了修改元素的方法。
特性:
- 可修改:支持
add()
、remove()
、set()
等操作,可动态改变元素和长度。 - 无固定实现:需通过具体实现类(如
ArrayList
)实例化。
与 List
的关系:MutableList
是 List
的子类型,即 MutableList
可以赋值给 List
变量(但反之不行)。
示例:
1 | val mutableList: MutableList<Int> = mutableListOf(1, 2, 3) |
ArrayList(动态数组实现类)
本质:MutableList
接口的具体实现类,基于动态数组(可自动扩容的数组)实现。
特性:
- 实现
MutableList
:支持所有增删改查操作。 - 动态扩容:当元素数量超过当前容量时,会自动创建更大的数组并复制元素。
- 随机访问高效:通过索引
get(index)
访问元素的时间复杂度为 O (1),但中间插入 / 删除元素效率低(需移动后续元素)。
与 mutableListOf()
的关系:mutableListOf()
默认返回 ArrayList
实例(除非指定其他实现)。
示例:
1 | val arrayList = arrayListOf(1, 2, 3) // 直接创建ArrayList |
对比与关联
对比
类型 | 性质 | 可修改性 | 长度是否固定 | 典型实现 / 特点 | 适用场景 |
---|---|---|---|---|---|
Array |
数组(类) | 可修改元素 | 固定 | 连续内存,基本类型优化 | 固定长度场景,与 Java 数组交互 |
List |
只读接口 | 不可修改 | 不固定(视图) | 无具体实现,依赖底层容器 | 仅查询数据,传递不可变数据 |
MutableList |
可变接口 | 可修改(增删改) | 不固定 | 定义修改方法,无具体实现 | 需要动态修改元素的场景(抽象接口) |
ArrayList |
实现类 | 可修改(增删改) | 不固定 | 动态数组,随机访问高效 | 频繁查询,较少中间插入 / 删除的动态列表场景 |
关键关联
ArrayList
是MutableList
的实现类,mutableListOf()
默认返回ArrayList
。List
可以是ArrayList
的只读视图(通过asList()
转换)。Array
是底层数据结构,而List
/MutableList
是更高层次的集合接口,提供更丰富的操作(如forEach
、filter
等)。
实际开发中,优先使用 listOf()
(只读)和 mutableListOf()
(可变),仅在需要数组特性(如固定长度、基本类型优化)时使用 Array
。
示例
不可变长
Array和List
1 | val arr0: Array<String> = arrayOf("A", "B") |
可变长
ArrayList 和 MutableList
1 | val list30: ArrayList<String> = arrayListOf("A", "B") |
字符串分割
1 | val nameList = "张三;李四;王五".split(';') |
注意
split操作返回的是List。
List转Array
1 | val nameArr = "张三;李四;王五".split(';').toTypedArray() |
map
1 | val optList = "ABCDEFGHIJKLMN".map { it + "" }.toTypedArray() |
注意
map操作返回的是List。
子数组
使用sliceArray
1 | val original = arrayOf(1, 2, 3, 4, 5) |
这个是前后都包含
1 | val useList = optList.sliceArray(0..optNum - 1) |
使用copyOfRange
对于原生类型数组(如 IntArray、DoubleArray 等),同样适用上述方法:
1 | val numbers = intArrayOf(10, 20, 30, 40, 50) |
这个是不包含最后
1 | val useList = optList.copyOfRange(0, optNum) |