首页 > 代码库 > 容器深入研究 --- 理解Map
容器深入研究 --- 理解Map
通常的:
映射表(也称关联数组)的基本思想是它维护的键-值(对)关联,因此你可以使用键来查找值。
标准的Java类库中包含了Map的几种实现,包括:HashMap,TreeMap,LinkedHashMap,WeakHashMap,ConcurrentHashMap,IdentityHashMap。
它们都有同样的基本接口Map,但是行为特性各不相同,这表现在效率、键值对的保存及呈现次序、对象的保存周期、映射表如何在多线程程序中工作的判定“键”等价的策略方面。Map接口实现的数量应该让你感觉到这种工具的重要性。
你可以获的对Map更深入的理解,这有助于观察关联数组是如何创建的。下面是一个极其简单的实现。
class AssociativeArray<K,V> { private Object[][] pairs; private int index; public AssociativeArray(int length) { pairs = new Object[length][2]; } public void put(K key, V value) { if (index >= pairs.length) { throw new ArrayIndexOutOfBoundsException(); } pairs[index++] = new Object[]{key, value}; } public V get(K key) { for (int i = 0; i < index; i ++) { if (key.equals(pairs[i][0])) { return (V) pairs[i][1]; } } return null; } @Override public String toString() { StringBuffer result = new StringBuffer(); for (int i = 0; i < index; i++) { result.append(pairs[i][0].toString()); result.append(":"); result.append(pairs[i][1].toString()); if (i < index - 1) { result.append("\n"); } } return result.toString(); } }
上面的本版是简单性的、缺乏效率性的,并且由于具有固定的尺寸显得够不灵活。
性能:
性能是映射表中的一个重要问题,当在get()中使用线性搜索时,执行速度回相当的慢,而这正是HashMap提高速度的地方。
HashMap使用了特殊的值,称作散列码,来取代对键的缓慢搜索。散列码是“相对唯一”的、用以代表对象的int值,它是通过将该对象的某些信息进行转换搜索而成的。
hashCode()是根类Object中的方法,因此所有Java对象都能产生散列码,HashMap就是使用对象的hashCode()进行快速查询的,此方法可以显著的提高性能。
下面是基本的Map实现。在HashMap上打星号表示如果没有其他的限制,它就应该成为你的默认选择,因为它对速度进行了优化。其他的都强调其他的特性,因此都不如HashMap快。
HashMap:
Map基于散列表的实现(它取代了HashTable)。插入和查询“键值对”的开销是固定的。可以通过构造器设置容量和负载因子,以调整容器的性能。
LinkedHashMap:
类似于HashMap,但是迭代遍历时,取得“键值对”的顺序是其插入次序,或者是最近最少使用(LRU)的次序。只比HashMap慢一点;而在迭代访问时反映更快,因为它使用的链表维护内部次序。
TreeMap:
基于红黑树的实现。查看“键”或“键值对”时,它们会被排序(次序由Comparable或者Comparator决定)。TreeMap特点在于,所得到的结果是经过排序的。TreeMap是唯一的带有subMap()方法的Map,它可以返回一个子树。
WeakHashMap:
弱键(weak key)映射,允许释放映射所指向的对象;这是为解决某类特殊问题而设计的。如果映射之外没有引用指向某个“键”,则此“键”可以被垃圾回收器回收。
ConcurrentHashMap:
一种线程安全的Map,它不涉及同步加锁。
IdentityHashMap:
使用==代替equals()对“键”进行比较的散列映射。专为解决特殊问题设计的。
散列是映射中存储元素的最常用的方式。
对Map中使用的键的要求与对Set中的元素的要求一样。任何键都必须有一个equals()方法;如果键被用于散列Map,那么它必须还具有恰当的hashCode()方法;如果键被用于TreeMap它必须实现Comparable。
SortedMap:
用SortedMap(TreeMap时期现阶段的唯一实现),可以确保键处于排序状态。这使得它具有额外的功能,这些功能是由SortedMap接口中的下列方法提供给的:
Comparator<? superK>
comparator()
返回对此映射中的键进行排序的比较器;如果此映射使用键的自然顺序,则返回null。Set<Map.Entry<K,V>>
entrySet()
返回在此映射中包含的映射关系的Set
视图。K
firstKey()
返回此映射中当前第一个(最低)键。SortedMap<K,V>
headMap(K toKey)
返回此映射的部分视图,其键值严格小于 toKey。Set<K>
keySet()
返回在此映射中所包含键的Set
视图。K
lastKey()
返回映射中当前最后一个(最高)键。SortedMap<K,V>
subMap(K fromKey,K toKey)
返回此映射的部分视图,其键值的范围从 fromKey(包括)到 toKey(不包括)。SortedMap<K,V>
tailMap(K fromKey)
返回此映射的部分视图,其键大于等于 fromKey。Collection<V>
values()
返回在此映射中所包含值的Collection
视图。
LindedHashMap:
为了提高速度,LinkedHashMap散列化所有的元素,但是在遍历键值对时,却又以元素的插入顺序返回键值对(System.out.println())。
此外,可以在构造器中设定LinkedHashMap,使之采用基于访问最近最少使用(LRU)算法,于是没有访问过的(可被看做需要删除的)元素就会出现在队列的掐面,对于需要定期清理元素以节省空间的程序来说,此功能是很容易实现的。