19.2 常用的几种集合类型
在前文我们介绍了集合接口,本节开始将介绍这些接口的实现类,这些集合包括非泛型和泛型集合,它们分别位于System.Collections命名空间和System.Collections.Generic命名空间。
非泛型集合中,主要介绍6个类:ArrayList、Hashtable、Queue、SortedList、Stack、BitArray。
这些非泛型集合类型的类图如图19-3所示。
图 19-3 常用的几种非泛型集合的类图
可见,所有的这些集合类都实现了IEnumerable和ICollection接口,因此它们都支持使用foreach语句进行迭代。实现IList接口的集合类共有1个:ArrayList;实现IDictionary节的集合类共有两个:SortedList和Hashtable;Queue、BitArray以及Stack这3个集合类直接实现ICollection和IEnumerable接口。
泛型集合中,主要介绍5个类:List<T>、HashSet<T>、LinkedList<T>、Stack<T>、Queue<T>。这些类的泛型集合类型的类图如图19-4所示。
图 19-4 常用的几种泛型集合
可见,所有的这些泛型集合类都实现了IEnumerable和IEnumerable<T>接口,它们同样支持使用foreach语句进行迭代。实现ISet<T>接口的集合类共有1个:Hashtable<T>;实现ICollection<T>和ICollection的集合类共有1个:SortedSet<T>;Stack<T>和Queue<T>这2个集合类实现了ICollection和IEnumerable<T>接口。
下面将分别学习这些常用的集合类型,其中泛型和非泛型版本将结合在一起进行讲解。
19.2.1 ArrayList
ArrayList实现了IList、ICollection、IEnumerable接口,如图19-5所示。
图 19-5 ArrayList的类图
ArrayList和Array的名字很相似,两者之间有相同的地方,也有不同的地方。通过将两者的对比进行学习,不失为一种好方法,既复习了数组的旧知识,又学习了集合的新知识,还能通过对比有新的收获。首先比较一下两者之间相同的地方,主要有:
❑两者都实现了IList、ICollection以及IEnumerable接口;
❑两者都可以使用整数索引访问集合中的元素,包括读取和赋值,且集合中的索引都从零开始。
然后是两者之间不同的地方,主要有:
❑ArrayList是集合,而Array是数组(数组也可以认为是一种特殊的集合);
❑ArrayList是具体类,而Array是抽象类,前者可实例化,后者不能,后者是所有数组的基类;
❑数组必须在实例化时指定元素的数量,该数量一旦确定就不可以再改变了;而ArrayList扩展了这一点,当实例化一个ArrayList实例时可以不指定集合元素数(此时该实例为空并且具有默认初始容量),也可以指定一个初始容量;
❑获取数组的元素数时使用Length属性,而获取ArrayList集合的元素数则使用Count属性;
❑数组可以有多维,而ArrayList只能是一维。
图19-6演示了ArrayList的结构。
图 19-6 ArrayList的结构
刚刚在ArrayList和Array之间进行了对比,相信读者已经能比较清楚地区分两者了。ArrayList类的主要特性如下:
❑ArrayList集合的元素只能为System.Object类型;
❑可以添加null值到集合中;
❑允许集合中的元素重复;
❑可以使用整数索引访问此集合中的元素,索引从零开始;
❑将引用类型的数据加入集合,元素的类型将向上转型成为Object类型,因此读取时将需要显式类型转换,存在类型转换失败的风险;
❑将值类型的数据加入集合中将“装箱”为Object类型,从集合中读取将“拆箱”为原来的值类型。
接下来看一下ArrayList类型的一些主要成员,例如构造函数、成员方法、属性等,在使用ArrayList类型前需要先做个简单了解。通过表19-2可知ArrayList类包含的一些成员方法及属性,其中包括它实现的多个接口中规定必须实现的成员,以及它自身的一些成员。
ArrayList有3个公共构造函数,如下:
❑public ArrayList()
初始化ArrayList类的新实例,该实例为空并且具有默认初始容量。
❑public ArrayList(ICollection c)
初始化ArrayList类的新实例,该实例包含从指定集合复制的元素并且具有与所复制的元素数相同的初始容量。
❑public ArrayList(int capacity)
初始化ArrayList类的新实例,该实例为空并且具有指定的初始容量。
除了前面已知的成员,ArrayList自己定义的一些主要成员如表19-3所示。
接下来使用一段例子代码来演示ArrayList的用法,代码清单19-1使用了两种方式来访问集合中的元素,分别是迭代器和for循环。
代码清单19-1 ArrayList代码示例
using System;
using System.Collections;
namespace ProgrammingCSharp4
{
class CollectionSample
{
public static void Main()
{
ArrayList books=new ArrayList();
books.Add("Programming C#4.0");
books.Add("Thinking in C++");
books.Add("Thinking in Java");
Console.WriteLine("Books");
Console.WriteLine("Count:{0}",books.Count);
Console.WriteLine("Capacity:{0}",books.Capacity);
Console.WriteLine("Values:");
Console.WriteLine();
Console.WriteLine("Use Iterator:");
PrintValues(books);
Console.WriteLine();
Console.WriteLine("Use for loop:");
PrintValues2(books);
}
//使用迭代器访问集合中的元素
private static void PrintValues(IEnumerable books)
{
foreach(object book in books)
{
Console.WriteLine(book);
}
}
//使用for循环访问集合中的元素
private static void PrintValues2(ArrayList books)
{
for(int i=0;i<books.Count;i++)
{
Console.WriteLine(books[i]);
}
}
}
}
上述代码运行的结果为:
Books
Count:3
Capacity:4
Values:
Use Iterator:
Programming C#4.0
Thinking in C++
Thinking in Java
Use for loop:
Programming C#4.0
Thinking in C++
Thinking in Java
请按任意键继续……