知识点思维导图

00. ArrayList集合
一、集合简介
在C#中,集合框架分为两大类:非泛型集合和泛型集合。这两类集合位于不同的命名空间,各有其适用场景。
1.1、非泛型集合 (System.Collections)
非泛型集合位于System.Collections命名空间下,它们可以存储任何类型的对象,但缺乏类型安全。这意味着在操作时需要进行装箱(将值类型转换为对象)和拆箱(将对象转换回值类型),可能导致性能开销和运行时错误。常见类包括:
- ArrayList:动态数组,可存储任意对象。
- Hashtable:键值对集合。
- Queue:先进先出队列。
- Stack:后进先出栈。
这些集合适用于早期C#版本或需要处理异构数据的场景,但现代开发中更推荐泛型集合。
1.2、泛型集合 (System.Collections.Generic)
泛型集合位于System.Collections.Generic命名空间下,引入类型参数(如T),提供编译时类型检查,避免装箱/拆箱开销。这提升了性能和安全性。常见类包括:
- List<T>:类型安全的动态列表。
- Dictionary<TKey, TValue>:键值对集合。
- Queue<T>:泛型队列。
- Stack<T>:泛型栈。
泛型集合是C# 2.0及以后版本的推荐选择,尤其在高性能应用中。
二、ArrayList
ArrayList是非泛型集合的核心代表,它基于数组实现,支持动态扩容。
2.1、ArrayList简介
ArrayList类位于System.Collections命名空间,用于存储对象集合。它允许添加、删除和索引访问元素,但所有元素以object类型存储。这使得ArrayList灵活但类型不安全。例如,存储整数时需要进行装箱:
ArrayList list = new ArrayList();
list.Add(10); // 装箱:int 转换为 object
int num = (int)list[0]; // 拆箱:object 转换为 int
ArrayList的优势在于动态大小:初始容量为0,添加元素时自动扩容(通常翻倍),避免数组的固定大小限制。
2.2、ArrayList的使用
ArrayList提供丰富的属性和方法,便于集合操作。
2.2.1 ArrayList的对象创建
创建ArrayList对象有多种方式:
// 方式1: 默认构造函数,初始容量为0
ArrayList list1 = new ArrayList();
// 方式2: 指定初始容量
ArrayList list2 = new ArrayList(10); // 初始容量为10
// 方式3: 从现有集合初始化
int[] array = {1, 2, 3};
ArrayList list3 = new ArrayList(array); // 将数组转换为ArrayList
2.2.2 ArrayList属性
常用属性包括:
- Count:获取当前元素数量。
- Capacity:获取或设置内部数组的容量(可优化内存使用)。
- IsFixedSize:返回
false,表示大小可变。 - IsReadOnly:返回
false,表示可修改。
示例:
ArrayList list = new ArrayList();
list.Add("A");
Console.WriteLine(list.Count); // 输出: 1
Console.WriteLine(list.Capacity); // 输出: 0 (初始状态)
2.2.3 ArrayList常用的方法
ArrayList支持多种操作方法,以下是核心功能:
-
添加元素
Add(object value):在末尾添加元素,平均时间复杂度为$O(1)$(扩容时为$O(n)$)。Insert(int index, object value):在指定索引插入元素,时间复杂度$O(n)$。
示例:
ArrayList list = new ArrayList(); list.Add("Apple"); // 添加元素 list.Insert(0, "Banana"); // 在索引0处插入 -
删除元素
Remove(object value):删除第一个匹配元素。RemoveAt(int index):删除指定索引元素。Clear():清空所有元素。
示例:
list.Remove("Apple"); // 删除"Apple" list.RemoveAt(0); // 删除索引0元素 list.Clear(); // 清空列表 -
查找元素
Contains(object value):检查元素是否存在。IndexOf(object value):返回第一个匹配索引(-1表示未找到)。
示例:
bool exists = list.Contains("Banana"); // true或false int index = list.IndexOf("Apple"); // 返回索引或-1 -
ArrayList的索引器(I操作) ArrayList支持索引访问,类似于数组:
list[0] = "Orange"; // 设置索引0元素 string item = (string)list[0]; // 获取索引0元素(需类型转换)索引器的时间复杂度为$O(1)$,但使用时需注意类型安全风险。
2.3、ArrayList与数组的区别
ArrayList和数组(如int[])在C#中有显著差异,以下是关键对比点:
-
类型系统
- 数组:类型安全,编译时检查元素类型(如
int[]只能存储整数)。 - ArrayList:非类型安全,存储
object类型,需要装箱/拆箱。
- 数组:类型安全,编译时检查元素类型(如
-
大小特性
- 数组:固定大小,声明后长度不可变。
- ArrayList:动态大小,自动扩容(通过
Capacity属性管理)。
-
性能比较
- 数组:访问速度快($O(1)$),无额外开销。
- ArrayList:添加/删除元素可能触发扩容($O(n)$),且装箱/拆箱增加开销。例如,存储值类型时,ArrayList的性能低于数组。
-
类型安全
- 数组:编译时类型检查,避免运行时错误。
- ArrayList:无编译时检查,可能导致
InvalidCastException。
-
初始化方式
- 数组:直接初始化(如
int[] arr = {1, 2, 3};)。 - ArrayList:需通过构造函数或方法添加元素。
- 数组:直接初始化(如
-
功能方法
- 数组:基本功能有限(如
Length属性)。 - ArrayList:提供丰富方法(如
Add,Remove,Sort)。
- 数组:基本功能有限(如
-
使用场景对比
- 数组:适用于固定大小、类型一致的数据(如数学计算)。
- ArrayList:适用于动态数据、混合类型场景(如旧版代码兼容)。
-
内存分配示例
- 数组:连续内存块,高效但不可变。
- ArrayList:基于数组实现,扩容时分配新数组并复制元素,内存开销更大。
示例:ArrayList扩容过程:
ArrayList list = new ArrayList(2); // 初始容量2 list.Add(1); // 使用现有容量 list.Add(2); list.Add(3); // 触发扩容:新容量=4,复制元素
三、List<T>泛型列表
List<T>是泛型集合的代表,提供类型安全和高效操作。
3.1 ArrayList与List<T>的相同与不同点
List<T>与ArrayList有相似功能,但关键差异在于类型处理:
- 相同点:两者都是动态数组,支持添加、删除、索引访问和扩容机制。
- 不同点:
- 类型安全:List<T>使用类型参数(如
List<int>),编译时检查,避免装箱/拆箱。 - 性能:List<T>操作更快(无装箱开销),平均时间复杂度类似(如Add为$O(1)$)。
- 命名空间:List<T>位于
System.Collections.Generic,ArrayList位于System.Collections。 - 初始化:List<T>支持集合初始化器(如
new List<int> {1, 2, 3})。
- 类型安全:List<T>使用类型参数(如
3.2 List<T>常用操作
List<T>提供直观的API,以下是基础操作:
-
创建 List
List<int> numbers = new List<int>(); // 空列表 List<string> names = new List<string>() {"Alice", "Bob"}; // 初始化 -
添加元素
Add(T item):末尾添加。Insert(int index, T item):指定索引插入。
示例:
numbers.Add(10); // 添加元素 numbers.Insert(0, 5); // 在索引0插入5 -
访问元素 使用索引器直接访问:
int first = numbers[0]; // 获取索引0元素 numbers[1] = 20; // 设置索引1元素 -
常用方法
Remove(T item):删除元素。RemoveAt(int index):删除索引元素。Contains(T item):检查存在性。Count属性:获取元素数量。
示例:
numbers.Remove(10); // 删除值为10的元素 bool hasFive = numbers.Contains(5); // true或false -
遍历 List 使用循环遍历:
foreach (int num in numbers) { Console.WriteLine(num); } // 或 for 循环 for (int i = 0; i < numbers.Count; i++) { Console.WriteLine(numbers[i]); }
3.3 高级操作
List<T>支持复杂操作,提升数据处理效率。
-
排序
Sort()方法:使用默认比较器排序(升序)。- 自定义排序:通过
Comparison<T>委托。
示例:
List<int> values = new List<int> {3, 1, 2}; values.Sort(); // 升序排序:1,2,3 // 自定义降序排序 values.Sort((a, b) => b.CompareTo(a)); -
查找
Find(Predicate<T> match):返回第一个匹配元素。FindAll(Predicate<T> match):返回所有匹配元素。BinarySearch(T item):有序列表中二分查找(高效$O(\log n)$)。
示例:
List<string> fruits = new List<string> {"Apple", "Banana", "Orange"}; string result = fruits.Find(f => f.StartsWith("B")); // "Banana" List<string> allB = fruits.FindAll(f => f.Length > 5); // ["Banana","Orange"] -
转换
ConvertAll<TOutput>(Converter<T, TOutput> converter):将列表元素转换为新类型。- 使用LINQ转换(如
Select)。
示例:
List<int> nums = new List<int> {1, 2, 3}; List<string> strings = nums.ConvertAll(x => x.ToString()); // ["1","2","3"]
总结
C# 中的集合分为非泛型(如 System.Collections 下的 ArrayList)和泛型两大类。非泛型的 ArrayList 以 object 类型存储任意元素,虽具备动态扩容的便利,但值类型必须装箱/拆箱,既损失性能又缺乏编译时类型检查;与固定大小的数组相比,它更灵活,但内存开销和运行时类型转换风险也更高。而泛型 List<T> 通过类型参数保证了类型安全,完全避免了装箱/拆箱,操作速度更快,同时提供了同样丰富的增删改查、排序、查找及转换等功能,是现代 C# 开发中处理动态数组的首选。

被折叠的 条评论
为什么被折叠?



