Delphi2009中容器类简介:
1.TList类:
一个可以存储指针的容器类,提供了一系列的方法和属性来添加,删除,重排,定位,存取和排序容器中的类,它是基于数组的机制来实现的容器,比较类似于C++中的Vector和Java中的ArrayList,TList 经常用来保存一组对象列表,基于数组实现的机制使得用下标存取容器中的对象非常快,但是随着容器中的对象的增多,插入和删除对象速度会直线下降,因此不适合频繁添加和删除对象的应用场景。
属性 | 描述 |
Count: Integer; | 返回列表中的项目数 |
Items[Index: Integer]: Pointer; default | 通过以0为底的索引下标直接存取列表中的项目 |
方法 | 类型 | 描述 |
Add(Item: Pointer): Integer; | 函数 | 用来向列表中添加指针 |
Clear; | 过程 | 清空列表中的项目 |
Delete(Index: Integer); | 过程 | 删除列表中对应索引的项目 |
IndexOf(Item: Pointer): Integer; | 函数 | 返回指针在列表中的索引 |
Insert(Index: Integer; Item: Pointer); | 过程 | 将一个项目插入到列表中的指定位置 |
Remove(Item: Pointer): Integer; | 函数 | 从列表中删除指针 |
名称 | 类型 | 描述 |
Capacity: Integer; | property | 可以用来获取或设定列表可以容纳的指针数目 |
Extract(Item: Pointer): Pointer; | function | Extract 类似于Remove 可以将指针从列表中删除,不同的是返回被删除的指针。 |
Exchange(Index1, Index2: Integer); | procedure | 交换列表中两个指针 |
First: Pointer; | function | 返回链表中的第一个指针 |
Last: Pointer; | function | 返回链表中最后一个指针 |
Move(CurIndex NewIndex: Integer); | procedure | 将指针从当前位置移动到新的位置 |
Pack; | procedure | 从列表中删除所有nil指针 |
Sort(Compare: TListSortCompare); | procedure | 用来对链表中的项目进行排序,可以设定Compare参数为用户定制的排序函数 |
测试代码:
- unit Unit1;
- interface
- uses
- Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
- Dialogs, StdCtrls;
- type
- TForm1 = class(TForm)
- Edit1: TEdit;
- procedure FormCreate(Sender: TObject);
- private
- { Private declarations }
- type
- TMyRec = record
- Id: Integer;
- Name : String;
- Age : Integer;
- end;
- PTMyRec = ^TMyRec;
- public
- { Public declarations }
- end;
- var
- Form1: TForm1;
- implementation
- {$R *.dfm}
- procedure TForm1.FormCreate(Sender: TObject);
- var
- PsnInfo : PTMyRec;
- PsnList : TList;
- begin
- PsnList := TList.Create;
- new(PsnInfo);
- PsnInfo^.Id := 1;
- PsnInfo^.Name := 'ShenBin';
- PsnInfo^.Age := 28;
- PsnList.Add(PsnInfo);
- PsnList.Add(PsnInfo);
- ShowMessage(IntToStr(PsnList.Count));
- end;
- end.
更多测试代码可参阅:http://www.cnblogs.com/del/archive/2007/12/29/1019566.html
2.TObjectList 类
TObjectList 类直接从TList 类继承,可以作为对象的容器。
不同于TList类,TObjectList类的Add, Remove, IndexOf, Insert等方法都需要传递TObject对象作为参数,由于有了编译期的强类型检查,使得TObjectList比TList更适合保存对象。此外TObjectList对象有OwnsObjects属性。当设定为True (默认值),同TList类不同,TObjectList对象将销毁任何从列表中删除的对象。无论是调用Delete, Remove, Clear 方法,还是释放TObjectList对象,都将销毁列表中的对象。有了TObjectList类,我们就再也不用使用循环来释放了对象。这就避免了释放链表对象时,由于忘记释放链表中的对象而导致的内存泄漏。 另外要注意的是OwnsObjects属性不会影响到Extract方法,TObjectList的Extract方法行为类似于TList,只是从列表中移除对象引用,而不会销毁对象。
TObjectList 对象还提供了一个FindInstanceOf 函数,可以返回只有指定对象类型的对象实例在列表中的索引。如果AExact 参数为True,只有指定对象类型的对象实例会被定位,如果AExact 对象为False,AClass 的子类实例也将被定位。AStartAt 参数可以用来找到列表中的多个实例,只要每次调用FindInstanceOf 函数时,将起始索引加1,就可以定位到下一个对象,直到FindInstanceOf 返回-1。下面是代码示意:
- var
- idx: Integer;
- begin
- idx := -1;
- repeat
- idx := ObjList.FindInstanceOf(TMyObject, True, idx+1);
- if idx >= 0 then
- ...
- until(idx < 0);
- end;
注意TComponentList 是从TObjectList类继承出来的,它的Add, Remove, IndexOf, Insert和 Items 方法调用都使用TComponent 类型的参数而不再是TObject类型,因此适合作为TComponent对象的容器。TComponentList 类还有一个特殊的特性,就是如果链表中的一个组件被释放的话,它将被自动的从TComponentList 链表中删除。这是利用TComponent的FreeNotification方法可以在组件被销毁时通知链表,这样链表就可以将对象引用从链表中删除的。
4.TClassList 类
不同于前面两个类,这个类继承于TList的类只是将Add, Remove, IndexOf, Insert和Items 调用的参数从指针换成了TClass元类类型。
5.TOrderedList, TStack和TQueue 类
要注意虽然TOrderedList 并不是从TList继承的,但是它在内部的实现时,使用了TList来储存指针。另外注意TOrderedList类的PushItem 过程是一个抽象过程,所以我们无法实例化 TOrderedList 类,而应该从TOrderedList继承新的类,并实现抽象的PushItem方法。TStack 和 TQueue 正是实现了PushItem抽象方法的类, 我们可以实例化TStack 和TQueue类作为后进先出的堆栈 (LIFO)和先进先出的队列(FIFO)。下面是这两个的的方法使用说明:
· Count 返回列表中的项目数。
· AtLeast 可以用来检查链表的大小,判断当前列表中的指针数目是否大于传递的参数值,如果为True表示列表中的项目数大于传来的参数。
· 对于TStack类Push 方法将指针添加到链表的最后,对于TQueue类Push 方法则将指针插入到链表的开始。
· Pop返回链表的末端指针,并将其从链表中删除。
· Peek返回链表的末端指针,但是不将其从链表中删除。
6.TObjectStack和TObjectQueue类
这两个类只是TStack和TQueue 类的简单扩展,在链表中保存的是TObject的对象引用,而不是简单的指针。
7.TIntList 类
到目前为止,我们看到的容器类中保存的都是指针或者对象引用(对象引用其实也是一种指针)。
那么我们能不能在链表中保存原生类型,如Integer,Boolean或者Double等呢。下面的我们定义的类TIntList 类就可以在链表中保存整数,这里我们利用了整数和指针都占用4个字节的存储空间,所以我们可以直接将指针映射为整数。
8.TStrings类
出于效率的考虑,Delphi并没有象C++和Java那样将字符串定义为类,因此TList本身不能直接存储字符串,而字符串列表又是使用非常广泛的,为此Borland提供了TStrings类作为存储字符串的基类,应该说是它除了TList类之外另外一个最重要的Delphi容器类。
要注意的是TStrings类本身包含了很多抽象的纯虚的方法,因此不能实例化后直接使用,必须从TStrings类继承一个基类实现所有的抽象的纯虚方法来进行实际的字符串列表管理。虽然TStrings类本身是一个抽象类,但是它应该说是一个使用了Template模式的模版类,提供了很多事先定义好的算法来实现添加添加、删除列表中的字符串,按下标存取列表中的字符串,对列表中的字符串进行排序,将字符串保存到流中。将每个字符串同一个对象关联起来,提供了键-值对的关联等等。
因为TStrings类本身是个抽象类,无法实例化,因此Delphi提供了一个TStringList的TStrings的子类提供了TStrings类的默认实现,通常在实际使用中,我们都应该使用TStringList类存储字符串列表,代码示意如下:
- var TempList: TStrings;
- begin
- TempList := TStringList.Create;
- try
- TempList.Add('字符串1');
- …
- finally
- TempList.Free;
- end;
- end;
9.TStrings类的常见的用法
根据下标存取列表中的字符串是最常见的一种操作,用法示意如下:
StringList1.Strings[0] := '字符串1';
注意在Delphi中,几乎所有的列表的下标都是以0为底的,也就是说Strings[0]是列表中的第一个字符串。另外,由于Strings属性是字符串列表类的默认属性,因此可以省略Strings,直接用下面的简便方法存取字符串:
StringList1[0] := '字符串1';
定位一个列表中特定的字符串的位置,可以使用IndexOf方法,IndexOf方法将会返回在字符串列表中的第一个匹配的字符串的索引值,如果没有匹配的字符串则返回-1。比如我们可以使用IndexOf方法来察看特定文件是否存在于文件列表框中,代码示意如下:
if FileListBox1.Items.IndexOf('TargetFileName') > -1 ...
有一点不方便的是TStrings类没有提供一个方法可以查找除了第一个匹配字符串外其他同样匹配的字符串的索引,只能是自己遍历字符串列表来实现,这点不如C++中的模版容器类以及相关的模版算法强大和方便。
下面是一个遍历字符串列表的示意,代码遍历列表框中的所有字符串,并将其全部转化为大写的字符串:
procedure TForm1.Button1Click(Sender: TObject);var Index: Integer;
begin
for Index := 0 to ListBox1.Items.Count - 1 do
ListBox1.Items[Index] := UpperCase(ListBox1.Items[Index]);
end;
前面我们看到了,要想向字符串列表中添加字符串,直接使用Add方法就可以了,但是Add方法只能将字符串加入到列表的末尾,要想在列表的指定位置添加字符串,需要使用Insert方法,下面代码在列表的索引为2的位置添加了字符串:
StringList1.Insert(2, 'Three');
如果要想将一个字符串列表中的所有字符串都添加到另一个字符串列表中,可以使用AddStrings方法,用法如下:
StringList1.AddStrings(StringList2);
要想克隆一个字符串列表的所有内容,可以使用Assign方法,例如下面的方法将Combox1中的字符串列表复制到了Memo1中:
Memo1.Lines.Assign(ComboBox1.Items);
要注意的是使用了Assign方法后,目标字符串列表中原有的字符串会全部丢失。
10.THashedStringList类
一般来说,通过键来查找值最简单的办法是遍历列表对列表中的键进行比较,如果相等则获取相应的键值。但是这种简单的办法也是效率最差的一种办法,当列表中的项目比较少时,这种办法还可以接受,但是如果列表中项目非常多的话,这种方法会极大的影响软件的运行速度。 这时我们可以使用哈希表来快速的通过键值来存取列表中的元素。由于本书并不是一本数据结构和算法的书,因此我无意在这里讨论哈希表背后的理论知识,我们只要知道哈希可以通过键快速定位相应的值就可以了,对此感兴趣的非计算机专业的人可以去察看相关的书,这里就不赘述了。
其他容器类请参阅:http://delphi.sharpplus.com/Delphi/delphi_collection.htm