# ArrayList 概念: `ArrayList` 是 C# 提供的一个==非泛型集合类== 本质上可以理解成:==一个长度可变的 `object` 数组== 它可以: 1. 像数组一样按下标访问 2. 自动扩容 3. 增删查改元素 4. 存储任意类型的对象 命名空间: ```csharp using System.Collections; ``` 注意: 是 `System.Collections` 不是 `System.Collection` ---- # 通常用法 1. 学习 C# 早期非泛型集合 2. 理解 `object`、装箱和拆箱 3. 存储数量不固定的数据 4. 对数组进行更方便的增删操作 实际开发中: 新代码更推荐使用 `List` `ArrayList` 主要作为进阶阶段理解集合历史和装箱拆箱的材料 ---- # 语法 创建: ```csharp ArrayList list = new ArrayList(); ``` 添加: ```csharp list.Add(数据); ``` 访问: ```csharp list[下标] ``` 长度: ```csharp list.Count ``` ---- # 基础案例 ```csharp using System; using System.Collections; ArrayList list = new ArrayList(); list.Add("小明"); list.Add(18); list.Add(true); Console.WriteLine(list[0]); Console.WriteLine(list[1]); Console.WriteLine(list[2]); Console.WriteLine(list.Count); ``` 理解: 1. `ArrayList` 内部存的是 `object` 2. 所以字符串、整数、布尔值都可以放进去 3. `Count` 表示当前实际存了多少个元素 ---- # 增删查改 增加: ```csharp ArrayList list = new ArrayList(); list.Add("A"); list.Add("B"); list.Insert(1, "C"); ``` 结果: ```text A C B ``` 删除: ```csharp list.Remove("A"); // 删除第一个匹配的元素 list.RemoveAt(0); // 删除指定下标的元素 list.Clear(); // 清空所有元素 ``` 查找: ```csharp bool hasB = list.Contains("B"); int index = list.IndexOf("B"); ``` 修改: ```csharp list[0] = "新的值"; ``` ---- # 遍历 使用 `for`: ```csharp ArrayList list = new ArrayList(); list.Add("A"); list.Add("B"); list.Add("C"); for (int i = 0; i < list.Count; i++) { Console.WriteLine(list[i]); } ``` 使用 `foreach`: ```csharp foreach (object item in list) { Console.WriteLine(item); } ``` 因为 `ArrayList` 中的元素都是按 `object` 看待,所以 `foreach` 变量常写成 `object`。 ---- # 取值时要类型转换 ```csharp ArrayList list = new ArrayList(); list.Add(100); int num = (int)list[0]; Console.WriteLine(num); ``` 原因: `list[0]` 的返回类型是 `object` 如果要当成 `int` 使用,就需要拆箱 / 强制类型转换 错误示意: ```csharp int num = list[0]; ``` 这样会报错,因为不能把 `object` 直接赋值给 `int`。 ---- # 装箱和拆箱问题 ```csharp ArrayList list = new ArrayList(); int hp = 100; list.Add(hp); // int 放进 object,发生装箱 int value = (int)list[0]; // object 取回 int,发生拆箱 ``` 理解: 1. 值类型放进 `ArrayList` 时,会发生装箱 2. 从 `ArrayList` 取出值类型时,需要拆箱 3. 装箱和拆箱都有额外开销 4. 类型转错还会运行时报错 这个点可以和[[万物之父和装箱与拆箱|装箱与拆箱]]一起理解。 ---- # Capacity 和 Count `Count`: 当前实际有多少个元素 `Capacity`: 内部数组当前能容纳多少个元素 ```csharp ArrayList list = new ArrayList(); Console.WriteLine(list.Count); Console.WriteLine(list.Capacity); list.Add("A"); list.Add("B"); Console.WriteLine(list.Count); Console.WriteLine(list.Capacity); ``` 理解: `ArrayList` 内部会自动扩容 `Count` 是实际数量 `Capacity` 是容量,不一定等于数量 ---- # 排序和反转 排序: ```csharp ArrayList list = new ArrayList(); list.Add(3); list.Add(1); list.Add(2); list.Sort(); ``` 反转: ```csharp list.Reverse(); ``` 注意: 如果里面混放了不能互相比较的类型,`Sort()` 可能会出错 例如: ```csharp list.Add(10); list.Add("A"); list.Sort(); // 可能出错 ``` 所以虽然 `ArrayList` 可以存任意类型,但最好不要随便混放。 ---- # 和数组的区别 | 对比点 | 数组 | ArrayList | | ---- | --------- | -------------- | | 长度 | 创建后固定 | 可以动态增删 | | 类型 | 通常固定一种类型 | 内部按 `object` 存 | | 访问 | 可以用下标 | 可以用下标 | | 性能 | 类型明确,性能较好 | 可能有装箱拆箱 | | 常用程度 | 基础常用 | 现在新项目较少用 | ---- # 常见错误 错误1:忘记引用命名空间 ```csharp ArrayList list = new ArrayList(); ``` 解决: ```csharp using System.Collections; ``` ---- 错误2:取值时忘记强转 ```csharp ArrayList list = new ArrayList(); list.Add(10); int num = list[0]; ``` 应该写: ```csharp int num = (int)list[0]; ``` ---- 错误3:混放类型后强转错误 ```csharp ArrayList list = new ArrayList(); list.Add("100"); int num = (int)list[0]; ``` `list[0]` 实际是字符串,不是整数,会出错。 ---- # 注意 1. `ArrayList` 在 `System.Collections` 命名空间中 2. `ArrayList` 是非泛型集合,内部按 `object` 存储 3. 它可以动态增删元素 4. 取出元素时通常需要强制类型转换 5. 值类型放入 `ArrayList` 会发生装箱 6. 不建议随意混放不同类型,容易产生转换错误 7. 新项目通常优先使用 `List`,类型更安全 ---- # 一句话记忆 ==ArrayList 是会自动扩容的 object 数组,方便但不够类型安全。== ---- # 面试/复习时怎么说 可以这样答: “ArrayList 是 `System.Collections` 命名空间下的非泛型集合,本质上可以理解为动态扩容的 `object` 数组。 它可以存储任意类型,但取值时通常需要强制类型转换,值类型放进去还会发生装箱。 所以它适合用来理解非泛型集合和装箱拆箱,新项目中一般更推荐使用泛型集合 `List`。” ---- 引用: 1. Microsoft Learn: [ArrayList Class](https://learn.microsoft.com/en-us/dotnet/api/system.collections.arraylist?view=net-9.0) 2. Microsoft Learn: [System.Collections Namespace](https://learn.microsoft.com/en-us/dotnet/api/system.collections?view=net-9.0) #ArrayList #集合 #进阶