Map、Set、Iterator迭代详解与 Java平台的集合框架
Map、Set、Iterator迭代详解
Map接口定义了四种类型的方法,每个Map都包含这些方法。
equals(Object o)比较指定对象与此Map的等价性。
hashCode()返回此Map的哈希码。
Map定义了几个用于插放和删除元素的变换方法。
remove(Object key) 从Map中删除键和关联的值。
put(object key,Object value) 将指定值与指定键相关联。
clear() 从Map虽删除所有映射。
putAll(Map t) 将指定Map中的所有映射复制到此Map。
查看Map
迭代Map中的元素不存在直接了当的方法。假如要查询某个Map以了解其哪些元素满足特定查询或假如要迭代其所有元素,则您首先需要获取该Map的 “视图”。有三种可能的视图:所有
键值对、所有键、所有值。前两个视图均返回Set对象,第三个视图返回Collection对象。就这两种情况而言,问题到这里并没有结束,这是因为您无法直接迭代Collection对象或Set对
象。要进行迭代,您必须获得一个Iterator对象。因此要迭代Map的元素,必须进行如下编码:
Iterator keyValuePairs = aMap.entrySet().iterator();
Iterator keys=aMap.keySet().iterator();
Iterator values=aMap.values().iterator();
值得注意的是,这些对象实际上是基础Map的视图,而不是包含所有元素的副本。
使用Iterator对象,您可以遍历Map的元素,还可以删除Map中的元素。
EnterySet()返回Map中所包含映射的Set视图。Set中的每个元素都是一个Map.Entry对象,可以使用getKey()和 getValue()方法访问后者的键元素和值元素。
keySet()返回Map中所包含键的Set视图。删除Set中的元素还将删除Map中相应原映射。
values()返回Map中所包含值的Collection视图。删除Collection中的元素还将删除Map中相应的映射
Map访问和测试方法:
get(Object key) 返回与指定键关联的值
containsKey(Object key) 假如Map包含指定键的映射,则返回True
isEmpty() 假如Map不包含键-值映射,则返回True
size() 返回Map中的键值映射的数目。
Set(interface):存入Set的每个元素必须是唯一的,因为Set不保存重复元素。加入Set的Object必须定义equals() 方法以确保对象的唯一性。
Set与Collection有完全一样的接口。Set接口不保证维护元素的次序。
迭代器是一种设计模式,它是一个对象,它可以遍历并选择序列中的对象,而开人员不需要了解该序列的底层结构。迭代器通常被称为“轻量级”对象,因为创建它的代价小。
Java中的Iterator功能比较简单,并且只能单向移动:使用方法iterator()要求容器返回一个Iterator。第一次调用 Iterator的next()方法时,它返回序列的第一个元素。使用next()获得序列中的
下一个元素。使用hasNext()检查序列中是否还有元素。使用remove()将迭代器新返回的元素删除。
Java平台的集合框架
“集合框架”主要由一组用来操作对象的接口组成。不同接口描述一组不同数据类型。
集合接口:6个接口,表示不同集合类型,是集合框架的基础。
抽象类:5个抽象类,对集合接口的部分实现。可扩展为自定义集合类。
实现类:8个实现类,对接口的具体实现。
在很大程度上,一旦您理解了接口,您就理解了框架。虽然您总要创建接口特定的实现,但访问实际集合的方法应该限制在接口方法的使用上;
因此,允许您更基本的数据结构而不必改变其它代码。
Collection接口是一组允许重复的对象。
Set接口继承Collection,但不允许重复,使用自己内部的排列机制。
List接口继承Collection,允许重复,以元素安插的次序来放置元素,不会重新排列。
Map接口是一组成对的键-值对象。Map中不能有重复的Key.拥有自己的内部排列机制。
容器中的元素类型都为Object。从容器取得元素时,必须把它转换成原来的类型。
集合接口:
Collection接口:用于表示任何对象或元素组。想要尽可能以常规方式处理一组元素时,就使用这一接口。
1、单元素添加、删除操作:
Boolean add(Object o):将对象添加到集合
Boolean remove (Object o):如果集体中有与O相匹配的对象,则删除对象O。
2、查询操作:
Int size():返回当前集合中元素的数量
Boolean isEmpty():判断集合中是否有任何元素。
Boolean contains(Object o):查找集合中是否否有对象O
Iterator iterator():返回一个迭代器,用来访问集合中的各个元素。
3、组操作:作用于元素组或整个集合
Boolean containsAll(Collection c):查找集合中是否含有集合C中所有元素
Boolean addAll(Collection c):将集合C中所有元素添加到该集合。
Void clear():删除集合中所有元素。
Void removeAll(Collection c):从集合中删除集合C中的所有元素。
Void retainAll(Collection c):从集合中删除集合C中不包含的元素
4、Collection转换为Object数组:
Object[] toArray():返回一个内含集合所有元素的Array
Object[] toArray(Object[] a):返回一个内含集合所有元素的Array.运行期返回的Array和参数A的型别相同,需要转换为正确型别。
此外,您还可以把集合转换成其它任何其它的对象数组。但是,您不能直接把集合转换成基本数据类型的数组,因为集合必须持有对象。 Collection不提供get()方法。如果要遍历
Collection中的元素,就必须用Iterator.
AbstractCollection抽象类
AbstactCollection类提供具体“集合框架”类的基本功能。虽然您可以自实现Collection接口的所有方法,但是,除了 Iterator()和Size()方法在恰当的子类中实现以外,其它所有方法都由
AbstractCollection类来提供实现。如果子类不覆盖某些方法,可选的方法将抛出异常。
Iterator接口
Collection接口的Iterator()方法返回一个Iterator。Iterator接口方法能以迭代方式逐个访问集合中各个元素,并安全的从Collection中除去适当的元素。
1、Boolean hasNext():判断是否存在另一个可访问的元素。
2、Object next():返回要访问的下一个元素。如果到达集合结尾,则抛出NoSuchElementException异常。
3、Void remove():删除上次访问返回的对象。本方法必须紧跟在一个元素的访问后执行。如果上次访问后集合已被修改,方法将抛出
IIIegalStateException。
Iterator中删除操作对底层Collection也有影响。
迭代器是故障快速修复的。这意味着,当另一个线程修改底层集合的时候,如果您正在用Iterator遍历集合,那么,Iterator就会抛出
ConcurrentModificationException异常并立刻失败。
List接口继承了Collection接口以定义一个允许重复项的有序集合。该接口不但能够对列表的一部分进行处理,还添加了面向位置的操作。
1、面向位置的操作包括插入某个元素,还包括获取、除去或更改元素的功能。在List中搜索元素可以从列表的头部或尾部开始,如果找到元素,还将报告元素所在的位置:
Void add(int index,Object element):在指定位置Index上添加元素element
Boolean addAll(int index,Collection c):将集合C的所有元素添加到指定位置Index
Object get(int index):返回List中指定位置的元素
Int indexOf(Object o):返回第一个出现元素O的位置,否则返回-1
Int lastIndexOf(Object o):返回最后一个出现元素O的位置,否则返回-1
Object remove(int index):删除指定位置上的元素
Object set(int index,Object element):用元素Element取代位置Index上的元素,并且返回旧的元素
2、List接口不但以位置序列迭代的遍历整个列表,还能处理集合的子集:
ListIterator ListIterator():返回一个列表迭代器,用来访问列表中的元素
ListIterator ListIterator(int index):返回一个列表迭代器,用来从指定位置Index开始访问列表中的元素
List subList(int formIndex,int toIndex):返回从指定位置FromIndex(包含)到ToIndex(不包含)范围中各个元素的列表视图对子列表的更改对底层List也有影响。
ListIterator接口继承Iterator接口以支持添加或更改底层集体中的元素,还支持双向访问。ListIterator没有当前位置,光标位于调用
Previous和Next方法返回的值之间。一个长度为N的列表,有N+1个有效索引值:
1、Void add(Object o):将对象O添加到当前位置的前面
Void set(Object o):用对象O替代Next或Previous方法访问的上一个元素。如果上次调用后列表结构被修改了,那么将抛出 IIIegalStateException异常。
2、Boolean hasPrevious():判断向后迭代时是否有元素可访问
Object previous():返回上一个对象
Int nextIndex():返回下次调用Next方法时将返回的元素的索引
Int previousIndex():返回下次调用Previous方法时将返回的元素的索引
有两个抽象的List实现类:AbstractList和AbstractSequentialList。它们覆盖了Equals()和 HashCode()方法以确保两个相等的集合返回相同的哈希码。
在“集合框架”中有两种常规的List实现:ArrayList和LinkedList。如果要支持随机访问,而不必在除尾部的任何位置插入或除去元素,那么,ArrayList提供了可选的集合。但如果,您要
频繁的从列表的中间位置添加和除去元素,而只要顺序的访问列表元素,那么,LinkedList实现更好。
ArrayList和LinkedList都实现Cloneable接口,都提供了两个构造函数,一个无参的,一个接受另一个 Collection。
LinkedList类添加了一些处理列表两端元素的方法。
1、Void addFirst(Object o):将对象O添加到列表的开头。
Void addLast(Object o):将对象O添加到列表的结尾
2、Object getFirst():返回列表开关的元素
Object getLast():返回列表结尾的元素
3、Object removeFirst():删除并且返回列表开关的元素
Object removeLast():删除并且返回列表结尾的元素
4、LinkedList():构建一个空的链接列表
Linked(Collection c):构建一个链接列表,并且添加集合C的所有元素使用这些新方法,您就可以轻松的把LinkedList当作一个堆栈、队列或其它面向端点的数据结构
ArrayList类封装了一个动态再分配的Object[]数组。每个ArrayList对象有一个Capacity。这个 Capacity表示存储列表中元素的数组的容量。当元素添加到ArrayList时,它的Capacity在常量
时间内自动增加。在向一个ArrayList对象添加大量元素的程序中,可使用ensureCapacity方法增加Capacity.这可以减少增加重分配的数量。
1、Void ensureCapacity(int minCapacity):将ArrayList对象容量增加MinCapacity
2、Void trimToSize():整理ArrayList对象容量为列表当前大小。程序可使用这个操作减少ArrayList对象存储空间。
Set接口继承Collection接口,而且它不允许集合中存在重复项,每个具体的Set实现类依赖添加的对象的Equals()方法来检查狂性。Set接口没有引入新方法,所以Set就是一个
Collection,只不过其行为不同。
Hash表是一种数据结构,用来查找对象。Hash表为每个对象计算出一个整数,称为Hash Code(哈希码)。Hash表是个链接式列表的阵列。每个列表称为一个Buckets(哈希表元)。
对象位置的计算Index=HashCode%buckets。
在“集合框架”中有两种比较接口:Comparable接口和Comparator接口。像String和Integer等Java内建类实现 Comparable接口以提供一定排序方式,但这样只能实现该接口一次。对
于那些没有实现Comparable接口的类、或者自定义的类,您可以通过Comparator接口来定义您自己的比较方式。
在Java.lang包中,Comparable接口适用于一个类有自然顺序的时候。假定对象集合是同一个类型,该接口允许您把集合排序成自然顺序。
Int compareTo(Object o):比较当前实例对象与对象O,如果位于对象O之前,返回负值,如果两个对象在排序中位置相同,则返回0,如果位于对象O后面,则返回正值。
SortedSet,它保持元素的有序顺序。SortedSet接口为集合的视图和它的两端提供了访问方法。当佻处理列表的子集时,理性视图会反映到源集。此外,更改源集也会反映在子集上。发
生这种情况的原因在于视图由两端的元素而不是下标元素指定,所以如果您想要一个特殊的高端元素在子集中,您必须找到下一个元素。添加到 SortedSet实现类的元素必须实现
Comparable接口,否则您必须给它的构造函数提供一个接口的实现。TreeSet类是它的唯一一分实现。
1、Comparator comparator():返回对元素进行排序时使用的比较器,如果使用Comparable接口的compareTo()方法对元素进行比较,则返回 Null。
2、Object first():返回有序集合中第一个元素。
3、Object last():返回有序集合中最后一个元素。
4、SortedSet subSet(Object fromElement,Object toElement):返回从formElement到ToElement范围内元素的SortedSet视图。
5、SortedSet headSet(Object toElemtn):返回SortedSet的一个视图,其内各元素皆小于Toelement
6、SortedSet tailSet(Object fromElement):返回SortedSet的一个视图,其内各元素皆大于或等于FromElement
AbstractSet类覆盖了Object类的equals()和hashCode()方法,以确保两个相等的集返回相同的哈希码。若两个集大小相等且包含相同元素,则这两个集相等。按定义,集的哈希码是集中
元素哈希码的总和。因此,不论集的内部顺序如何,两个相等的集合有相同的哈希码。
Object类
1、Boolean equals(Object obj):对两个对象进行比较,以便确定它们是否相同
2、Int hashCode():返回该对象的哈希码。相同的对象必须返回相同的哈希码
“集合框架”支持Set接口两种普通的实现:HashSet和TreeSet。HashSet存储重复自由的集合。当您要从集合中以有序的方式插入和抽取元素时,TreeSet实现会有用处。为了能顺利进
行,添加到TreeSet的元素必须是可排序的。
HashSet类
1、HashSet():构建一个空的哈希集
2、HashSet(Collection c):构建一个哈希集,并且添加集合C中所有元素
3、HashSet(int initialCapacity):构建一个拥有特定容量的空哈希集
4、HashSet(int initialCapacity,float loadFactor):构建一个拥有特定容量和加载因子的空哈希集。LoadFactor是0至1之间的一个数
TreeSet类
1、TreeSet():构建一个空的树集
2、TreeSet(Collection c):构建一个树集,并且添加集合C中所有元素
3、TreeSet(Comparator c):构建一个树集,并且使用特定的比较器对其元素进行排序
4、TreeSet(SortedSet S):构建一个树集,添加有序集合S中所有元素,并且使用与有序集合S相同的比较器排序。
LinkedHashSet的迭代器按照元素的插入顺序来访问各个元素。它提供了一个可以快速访问各个元素的有序集合。同时,它也增加了实现的代价,因为哈希表元中的各个元素是通过双重
链接式列表链接在的。
1、LinkedHashSet():构建一个空的链接式哈希集
2、LinkedHashSet(Collection c):构建一个链接式哈希集,并且添加集合C中所有元素
3、LinkedHashSet(int initialCapacity):构建一个拥有特定容量的空链接式哈希集
4、LinkedHashSet(int initialCapacity,float loadFactor):构建一个拥有特定容量和加载因子的空链接式哈希集。LoadFactor是0至1之间的一个数。
Map接口用于维护键/值对。该接口描述了从不重复的键到值的映射
1、添加、删除操作
Object put(Object key,Object value):将互相关联的一个关键字与一个值放入该映像。如果该关键字已经存在,那么与此关键字相关的新值
将取代旧值。方法返回关键字的旧值,如果关键字原先并不存在,则返回Null
Object remove(Object key):从映像中删除与Key相关的映射
Void putAll(Map t):将来自特定映像的所有元素添加到该映像
Void clear():从映像中删除所有映射
2、查询操作:
Object get(Object key):获得与关键字Key相关的值,并且返回与关键字Key相关的对象,如果没有在该映像中找到该关键字,则返回Null
Boolean containsKey(Object key):判断映像中是否存在关键字Key
Boolean containsValue(Object value):判断映像中是否存在值Value
Int size():返回当前映像中映射的数量
Boolean isEmpty():判断映像中是否有任何映射
3、视图操作:处理映像中键/值对组
Set keySet():返回映像中所有关键字的视图集
Collection values():返回映像中所有值的视图集
Set entrySet():返回Map.Entry对象的视图集,即映像中的关键字/值对
Map的entrySet()方法返回一个实现Map.Entry接口的对象集合。集合中每个对象都是底层Map中一个特定的键/值对。通过这个集合的迭代器,您可以获得每一个条目的键或值并对值进行更
改。当条目通过迭代器返回后,除非是迭代器自身的remove()方法或者迭代器返回的条目的setValue()方法,其余对源Map外部的修改都会导致此条目集变得无效,同时产生条目行为未定
义。
Object getKey():返回条目的关键字
Object getValue():返回条目的值
Obect setValue(Object value):将相关映像中的值改为value,并且返回旧值。
“集合框架”提供了个特殊的Map接口:SortedMap,它用来保持键的有序顺序。SortedMap接口为映像的视图(子集),包括两个端点提供了访问方法。除了排序是作用于映射的键以
外,处理SortedMap和处理SortedSet一样。添加到SortedMap实现类的元素必须实现Comparable接口,否则您必须给它的构造函数提供一个Comparator接口的实现。TreeMap类是它的
唯一一份实现。
“因为对于映射来说,每个键只能对应一个值,如果在添加一个键/值对时比较两个键产生了0返回值(通过Comparable的 compareTo()方法或通过Comparator的compare()方法),
那么,原始键对应值被新的值替代。如果两个元素相等,那还好。但如果不相等,那么您就应该修改比较方法,让比较方法和 equals() 的效果一致。”
(1) Comparator comparator(): 返回对关键字进行排序时使用的比较器,如果使用Comparable接口的compareTo()方法对关键字进行比较,则返回null
(2) Object firstKey(): 返回映像中第一个(最低)关键字
(3) Object lastKey(): 返回映像中最后一个(最高)关键字
(4) SortedMap subMap(Object fromKey, Object toKey): 返回从fromKey(包括)至toKey(不包括)范围内元素的SortedMap视图(子集)
(5) SortedMap headMap(Object toKey): 返回SortedMap的一个视图,其内各元素的key皆小于toKey
(6) SortedSet tailMap(Object fromKey): 返回SortedMap的一个视图,其内各元素的key皆大于或等于fromKey
4.3. AbstractMap抽象类
和其它抽象集合实现相似,AbstractMap 类覆盖了equals()和hashCode()方法以确保两个相等映射返回相同的哈希码。如果两个映射大小相等、包含同样的键且每个键在这两个映射
中对应的值都相同,则这两个映射相等。映射的哈希码是映射元素哈希码的总和,其中每个元素是Map.Entry接口的一个实现。因此,不论映射内部顺序如何,两个相等映射会报告相同的
哈希码。
4.4. HashMap类和TreeMap类
“集合框架”提供两种常规的Map实现:HashMap和TreeMap (TreeMap实现SortedMap接口)。在Map 中插入、删除和定位元素,HashMap 是最好的选择。但如果您要按自然顺序
或自定义顺序遍历键,那么TreeMap会更好。使用HashMap要求添加的键类明确定义了hashCode()和equals()的实现。
这个TreeMap没有调优选项,因为该树总处于平衡状态。
4.4.1. HashMap类
为了优化HashMap空间的使用,您可以调优初始容量和负载因子。
(1) HashMap(): 构建一个空的哈希映像
(2) HashMap(Map m): 构建一个哈希映像,并且添加映像m的所有映射
(3) HashMap(int initialCapacity): 构建一个拥有特定容量的空的哈希映像
(4) HashMap(int initialCapacity, float loadFactor): 构建一个拥有特定容量和加载因子的空的哈希映像
4.4.2. TreeMap类
TreeMap没有调优选项,因为该树总处于平衡状态。
(1) TreeMap():构建一个空的映像树
(2) TreeMap(Map m): 构建一个映像树,并且添加映像m中所有元素
(3) TreeMap(Comparator c): 构建一个映像树,并且使用特定的比较器对关键字进行排序
(4) TreeMap(SortedMap s): 构建一个映像树,添加映像树s中所有映射,并且使用与有序映像s相同的比较器排序
4.5. LinkedHashMap类
LinkedHashMap扩展HashMap,以插入顺序将关键字/值对添加进链接哈希映像中。象LinkedHashSet一样,LinkedHashMap内部也采用双重链接式列表。
(1) LinkedHashMap(): 构建一个空链接哈希映像
(2) LinkedHashMap(Map m): 构建一个链接哈希映像,并且添加映像m中所有映射
(3) LinkedHashMap(int initialCapacity): 构建一个拥有特定容量的空的链接哈希映像
(4) LinkedHashMap(int initialCapacity, float loadFactor): 构建一个拥有特定容量和加载因子的空的链接哈希映像
(5) LinkedHashMap(int initialCapacity, float loadFactor,
boolean accessOrder): 构建一个拥有特定容量、加载因子和访问顺序排序的空的链接哈希映像
“如果将accessOrder设置为true,那么链接哈希映像将使用访问顺序而不是插入顺序来迭代各个映像。每次调用get或者put方法时,相关的映射便从它的当前位置上删除,然后放到链
接式映像列表的结尾处(只有链接式映像列表中的位置才会受到影响,哈希表元则不受影响。哈希表映射总是待在对应于关键字的哈希码的哈希表元中)。”
“该特性对于实现高速缓存的“删除最近最少使用”的原则很有用。例如,你可以希望将最常访问的映射保存在内存中,并且从数据库中读取不经常访问的对象。当你在表中找不到
某个映射,并且该表中的映射已经放得非常满时,你可以让迭代器进入该表,将它枚举的开头几个映射删除掉。这些是最近最少使用的映射。”
(6) protected boolean removeEldestEntry(Map.Entry eldest): 如果你想删除最老的映射,则覆盖该方法,以便返回true。当某个映射已经添加给映像之后,便调用该方法。它的默认
实现方法返回false,表示默认条件下老的映射没有被删除。但是你可以重新定义本方法,以便有选择地在最老的映射符合某个条件,或者映像超过了某个大小时,返回true。
4.6. WeakHashMap类
WeakHashMap是Map的一个特殊实现,它使用WeakReference(弱引用)来存放哈希表关键字。使用这种方式时,当映射的键在 WeakHashMap的外部不再被引用时,垃圾收集器会
将它回收,但它将把到达该对象的弱引用纳入一个队列。WeakHashMap的运行将定期检查该队列,以便找出新到达的弱应用。当一个弱引用到达该队列时,就表示关键字不再被任何人
使用,并且它已经被收集起来。然后WeakHashMap便删除相关的映射。
(1) WeakHashMap(): 构建一个空弱哈希映像
(2) WeakHashMap(Map t): 构建一个弱哈希映像,并且添加映像t中所有映射
(3) WeakHashMap(int initialCapacity): 构建一个拥有特定容量的空的弱哈希映像
(4) WeakHashMap(int initialCapacity, float loadFactor): 构建一个拥有特定容量和加载因子的空的弱哈希映像
4.6. IdentityHashMap类
IdentityHashMap也是Map的一个特殊实现。在这个类中,关键字的哈希码不应该由hashCode()方法来计算,而应该由 System.identityHashCode方法进行计算(即使已经重新定义了
hashCode方法)。这是Object.hashCode根据对象的内存地址来计算哈希码时使用的方法。另外,为了对各个对象进行比较,IdentityHashMap将使用==,而不使用equals方法。
换句话说,不同的关键字对象,即使它们的内容相同,也被视为不同的对象。IdentityHashMap类可以用于实现对象拓扑结构转换 (topology-preserving object graph transformations)
(比如实现对象的串行化或深度拷贝),在进行转换时,需要一个“节点表”跟踪那些已经处理过的对象的引用。即使碰巧有对象相等,“节点表”也不应视其相等。另一个应用是维护代理
对象。比如,调试工具希望在程序调试期间维护每个对象的一个代理对象。
“IdentityHashMap类不是一般意义的Map实现!它的实现有意的违背了Map接口要求通过equals方法比较对象的约定。这个类仅使用在很少发生的需要强调等同性语义的情况。”
(1) IdentityHashMap (): 构建一个空的全同哈希映像,默认预期最大尺寸为21“预期最大尺寸是映像期望把持的键/值映射的最大数目”
(2) IdentityHashMap (Map m): 构建一个全同哈希映像,并且添加映像m中所有映射
(3) IdentityHashMap (int expectedMaxSize): 构建一个拥有预期最大尺寸的空的全同哈希映像。放置超过预期最大尺寸的键/值映射时,将引起内部数据结构的增长,有时可能很费时。