Java集合容器主要有以下几类:
1,内置容器:数组
2,list容器:Vetor,Stack,ArrayList,LinkedList,
CopyOnWriteArrayList(1.5),AttributeList(1.5),RoleList(1.5),RoleUnresolvedList(1.5),
ConcurrentLinkedQueue(1.5),ArrayBlockingQueue(1.5),LinkedBlockingQueue(1.5),
PriorityQueue(1.5),PriorityBlockingQueue(1.5),SynchronousQueue(1.5)
3,set容器:HashSet(1.2),LinkedHashSet(1.4),TreeSet(1.2),
CopyOnWriteArraySet(1.5),EnumSet(1.5),JobStateReasons。
4,map容器:Hashtable,HashMap(1.2),TreeMap(1.2),LinkedHashMap(1.4),WeakHashMap(1.2),
IdentityHashMap(1.4),ConcurrentMap(1.5),concurrentHashMap(1.5)。
注意:Vector,Stack,Hashtable是Java1.2前的容器。
虽然在Java2之前,Java是没有完整的集合框架的。它只有一些简单的可以自扩展的容器类。
但是在Java2后他们还是被融入到了集合框架的,不过只是历史遗留而已。它们和1.2前应该还是有些变化的,虽然本质没什么变化。
Set接口继承于Collection,但不允许重复,使用自己内部的一个排列机制。
List接口继承Collection,允许重复,以元素安插的次序来放置元素,不会重新排列。
Map接口是一组成对的键-值对象,即所持有的是key-value pairs。Map中不能有重复的key。拥有自己的内部排列机制。
一、Java1.2之前的容器类库
其实在Java2之前,Java是没有完整的集合框架的。它只有一些简单的可以自扩展的容器类,比如Vector,Stack,Hashtable等。
Java1容器类库设计的一个重大失误是竟然没有对容器进行排序的工具。比如你想让Vector容器中的对象按字典顺序进行排序,你就要自己实现。
1.1、Vector
java.util.Vector中包含的元素可以通过一个整型的索引值取得,它的大小可以在添加或移除元素时自动增加或缩小。Vector的操作很简单,通过addElement()加入一个对象,用elementAt()取出它,还可以查询当前所保存的对象的个数size();
另外还有一个Enumeration类提供了连续操作Vector中元素的方法,这可以通过Vector中的elements()方法来获取一个Enumeration类的对象,
可以用一个While循环来遍历其中的元素。用hasMoreElements()检查其中是否还有更多的元素。
用nextElement()获得下一个元素。Enumeration的用意在于使你能完全不用理会你要遍历的容器的基础结构,只关注你的遍历方法,
这也就使得遍历方法的重用成为可能。由于这种思想的强大功能,所以在Java2中被保留下来,不过具体实现,方法名和内部算法都改变了,
这就是Java2中的Iterator以及ListIterator类。然而Enumeration的功能却十分有限,比如只能朝一个方向进行,只能读取而不能更改等。
更多内容请参考《Vector》
1.2、Stack
java.util.Stack最常用的操作便是压入和弹出,最后压入的元素最先被弹出。它遵循后进先出(LIFO)原则。
在Java中Stack的的用法也很简单,有push()压入一个元素,用pop()弹出一个元素。
更多内容请参考《Stack容器》
1.3、Hashtable
Hashtable与Java2中的Map类似,可以看成一种关联或映射数组,可以将两个毫无关系的对象相关联。
它的基本目标是实现两个对象之间进行关联。
更多内容请参考《Hashtable》
二、Java2中的容器类库
自Java1.2之后Java版本统称为Java2,Java2中的容器类库才可以说是一种真正意义上的集合框架的实现。
基本完全重新设计,但是又对Java1中的一些容器类库在新的设计上进行了保留,这主要是为了向下兼容的目的,
当用 Java2开发程序时,应尽量避免使用它们,Java2的集合框架已经完全可以满足你的需求。
在Java1中容器类库是同步化的,而 Java2中的容器类库都是非同步化,这可能是对执行效率进行考虑的结果。
Java2中的集合框架提供了一套设计优良的接口和类,使程序员操作成批的数据或对象元素极为方便。
这些接口和类有很多对抽象数据类型操作的API,而这是我们常用的且在数据结构中熟知的。例如Maps,Sets,Lists,Arrays等。
并且Java用面向对象的设计对这些数据结构和算法进行了封装,这就极大的减化了程序员编程时的负担。
程序员也可以以这个集合框架为基础,定义更高级别的数据抽象,比如栈、队列和线程安全的集合等,从而满足自己的需要。
Java2的集合框架,抽其核心,主要有三类:List(包括List,Queue,BlockingQueue)、Set和Map。List和Set继承了Collection,而Map则独成一体。
初看上去可能会对Map独成一体感到不解,它为什么不也继承Collection呢?但是这种设计是合理的。
一个Map提供了通过Key对Map中存储的Value进行访问,也就是说它操作的都是成对的对象元素,比如put()和get()方法,
而这是一个Set或List 所不就具备的。当然在需要时,你可以由keySet()方法或values()方法从一个Map中得到键的Set集或值的Collection集。
集合框架中还有两个很实用的公用类:Collections和Arrays。Collections提供了对一个Collection容器进行诸如排序、复制、查找和填充等一些非常有用的方法, Arrays则是对一个数组进行类似的操作。
2.1、Collection
Collection接口提供了一组操作成批对象的方法。(它只是个接口)
它提供了基本操作如添加、删除。它也支持查询操作如是否为空isEmpty()方法等。
为了支持对Collection进行独立操作,Java的集合框架给出了一个Iterator,它使得你可以泛型操作一个Collection,
而不需知道这个 Collection的具体实现类型是什么。它的功能与Java1中的Enumeration类似,只是更易掌握和使用,功能也更强大。
在建立集合框架时,Sun的开发团队考虑到需要提供一些灵活的接口,用来操作成批的元素,又为了设计的简便,
就把那些对集合进行可选操作的方法与基本方法放到了一起。因为一个接口的实现者必须提供对接口中定义的所有方法的实现,
这就需要一种途径让调用者知道它正在调用 的可选方法当前不支持。最后开发团队选择使用一种信号,
也即抛出一种不支持操作例外(UnsupportedOperationException),如果你在使用一个Collection中遇到一个上述的例外,
那就意味着你的操作失败,比如你对一个只读Collection添加一个元素时,你就会得到一个不支持操作例外。
在你实现一个集合接口时,你可以很容易的在你不想让用户使用的方法中抛出UnsupportOperationException来告诉使用者这个方法当前没有实现,
UnsupportOperationException是RuntimeException的一个扩展。
另外Java2的容器类库还有一种Fail fast的机制。比如你正在用一个Iterator遍历一个容器中的对象,
这时另外一个线程或进程对那个容器进行了修改,那么再用next()方法时可能会有灾难性的后果,
而这是你不愿看到的,这时就会引发一个ConcurrentModificationException例外。
这就是 fail-fast。
声明的接口
Public Methods | |
abstract boolean | add(E object) Attempts to add 确保容器能持有你传给它的那个参数。如果没有把它加进去,就返回false。(“可选”) |
abstract boolean | addAll(Collection<? extends E> collection) Attempts to add all of the objects contained in 加入参数Collection所含的所有元素。只要加了元素,就返回true。 |
abstract void | clear() Removes all elements from this 清除容器所保存的所有元素。(“可选”) |
abstract boolean | contains(Object object) Tests whether this 如果容器持有参数Object,就返回true。 |
abstract boolean | containsAll(Collection<?> collection) Tests whether this 如果容器持有参数Collection所含的全部元素,就返回true。 |
abstract boolean | Compares the argument to the receiver, and returns true if they represent the same object using a class specific comparison. |
abstract int | hashCode() Returns an integer hash code for the receiver. |
abstract boolean | isEmpty() Returns if this 如果容器里面没有保存任何元素,就返回true。 |
abstract Iterator<E> | iterator() Returns an instance of 返回一个可以在容器的各元素之间移动的Iterator。 |
abstract boolean | Removes one instance of the specified object from this 删除容器里面某个元素。删过东西,就返回true。(“可选”) |
abstract boolean | removeAll(Collection<?> collection) Removes all occurrences in this 删除容器里面所有参数Collection所包含的元素。只要删过东西,就返回true。(“可选”) |
abstract boolean | retainAll(Collection<?> collection) Removes all objects from this 删除容器中参数Collection所制定之外的所有元素(集合论中“交集”的概念)。如果发生过变化,则返回true。(“可选”) |
abstract int | size() Returns a count of how many objects this |
abstract <T> T[] | toArray(T[] array) Returns an array containing all elements contained in this If the specified array is large enough to hold the elements, the specified array is used, otherwise an array of the same type is created. If the specified array is used and is larger than this Collection, the array element following the Collection elements is set to null. If the implementation has ordered elements it will return the element array in the same order as an iterator would return them. toArray(new Object[0]) behaves exactly the same way as toArray() does. |
abstract Object[] | toArray() Returns a new array containing all elements contained in this |
注意,这里没有能进行随机访问的get()方法。这是因为Collection有个子接口Set。而Set有它自己的内部顺序(因此随即访问事毫无意义的)。
所以如果你要检查Collection的元素,你就必须使用迭代器。
如下:
String key="key";
String value="Hello";
String value2="Hi";
HashMap <String ,String> map=new HashMap();
map.put(key, value);
map.put(key+2, value2);
Collection<String> c=map.values();
for(String str:c)
{
System.out.println(str);
}
注意1:Collection直接子接口有List<E>,Queue<E>,BlockingQueue<E>,Set<E>,SortedSet<E>,BeanContext, BeanContextServices。
2.2、List
java.util.List接口对Collection进行了简单的扩充
它的具体实现类常用的有ArrayList和LinkedList。你可以将任何东西放到一个 List容器中,并在需要时从中取出。
ArrayList从其命名中可以看出它是一种类似数组的形式进行存储,因此它的随机访问速度极快,
而 LinkedList的内部实现是链表,它适合于在链表中间需要频繁进行插入和删除操作。
在具体应用时可以根据需要自由选择。
前面说的Enumeration和Iterator只能对容器进行向前遍历,而ListIterator则继承了Iterator的思想,并提供了对List进行双向遍历的方法。
List继承了来自Collection的iterator()来获取这个序列的Iterator
List提供了以两个方法获取这个序列的ListIterator,
abstract ListIterator<E> listIterator()
abstract ListIterator<E> listIterator(int location)
关于ListIterator的更多内容请参照《ListIterator》
2.2.1、ArrayList
java.util.ArrayList是一个用数组实现的List。能进行快速的随机访问,但是往列表中间插入和删除元素的时候比较慢。
更多内容请参考《ArrayList》
2.2.2、LinkedList
java.util.LinkedList(链表)-是双向链表,每个节点都有两个指针指向上一节点和下一节点。
对顺序访问进行了优化。在List中间插入和删除元素的代价也不高。
随机访问的速度相对较慢。此外它还有 addFirst(),addLast(),getFirst(),getLast(),removeFirst()和removeLast()等方法.
你能把它当成栈(stack),队列(queue)或双向队列(deque)来用。
关于LinkedList的更多内容请参考《LinkedList》
2.2.3、CopyOnWriteArrayList(1.5)
CopyOnWriteArrayList是ArrayList 的一个线程安全的变体,
其中所有可变操作(添加、设置,等等)都是通过对基础数组进行一次新的复制来实现的。
这一般需要很大的开销,但是当遍历操作的数量大大超过可变操作的数量时,这种方法可能比其他替代方法更 有效。
在 不能或不想进行同步遍历,但又需要从并发线程中排除冲突时,它也很有用。
“快照”风格的迭代器方法在创建迭代器时使用了对数组状态的引用。此数组在迭代器的生存期内绝不会更改,
因此不可能发生冲突,并且迭代器保证不会抛出 ConcurrentModificationException。
自创建迭代器以后,迭代器就不会反映列表的添加、移除或者更改。不支持迭代器上更改元素的操作(移除、设置和添加)。
这些方法将抛出 UnsupportedOperationException。
2.2.4、AttributeList(1.5)
AttributeList表示Attribute对象的列表.它继承于ArrayList.为了在ArrayList中插入Attribute对象,而重写超类 ArrayList 中的相应方法。
它为了确保 AttributeList 中所包含的对象只是Attribute对象,这是必需的。
这可避免在检索 AttributeList 中的元素时出现异常。
2.2.5、RoleList(1.5)
RoleList 表示角色(Role 对象)的列表.它继承于ArrayList.它为了在ArrayList中插入Role对象,而重写超类ArrayList中的相应方法。
RoleUnresolvedList(1.5)
RoleUnresolvedList表示RoleUnresolved 对象的列表.它继承于ArrayList.
它为了在ArrayList中插入RoleUnresolved对象,而重写超类ArrayList中的相应方法。
2.2.6、ConcurrentLinkedQueue(1.5)
一个基于链接节点的、无界的、线程安全的队列。
此队列按照 FIFO(先进先出)原则对元素进行排序。队列的头部 是队列中时间最长的元素。
队列的尾部 是队列中时间最短的元素。新的元素插入到队列的尾部,队列检索操作从队列头部获得元素。
当许多线程共享访问一个公共 collection 时,ConcurrentLinkedQueue 是一个恰当的选择。此队列不允许 null 元素。
此实现采用了有效的“无等待 (wait-free)”算法,该算法基于 Maged M. Michael 和 Michael L. Scott 撰写的
《 Simple, Fast, and Practical Non-Blocking and Blocking Concurrent Queue Algorithms》中描述的算法。
需要小心的是,与大多数 collection 不同,size 方法不是一个固定时间的操作。
由于这些队列的异步特性,确定当前元素的数量需要遍历这些元素。
此类及其迭代器实现了 Collection 和 Iterator 接口的所有可选 方法。
注意1:它的线程安全不是通过锁来实现的。它是通过非阻塞算法来实现的。
关于非阻塞算法请参阅《Java非阻塞算法简介》,《ConcurrentLinkedQueue原理(上) 》和《ConcurrentLinkedQueue原理(下)
》
注意2:此队列不允许 null 元素
关于ConcurrentLinkedQueue的更加详细参阅《ConcurrentLinkedQueue》
2.2.7、BlockingQueue(1.5)
BlockingQueue接口是在Queue基础上增加了两个操作,
两个操作是:检索元素时等待队列变为非空,以及存储元素时等待空间变得可用。
(试图向已满队列中放入元素会导致放入操作受阻塞,直到BlockingQueue里有新的空间才会被唤醒继续操作。
试图从空队列中检索元素将导致类似阻塞,直到BlocingkQueue进了新货才会被唤醒。)
BlockingQueue的实现类有ArrayBlockingQueue, LinkedBlockingQueue, DelayQueue,PriorityBlockingQueue, SynchronousQueue。
关于BlockingQueue及其实现类的详细信息请参考《BlockingQueue》
2.2.8、PriorityQueue
PriorityQueue是个基于优先级堆的极大优先级队列。
具体参考《PriorityBlockingQueue》
2.3、Set
java.util.Set接口也是Collection的一种扩展,它的接口都是来自Collection或Iterable,它自己并没新增加接口.
Set是一个不包含重复元素的 collection。更正式地说,set 不包含满足e1.equals(e2) 的元素对 e1 和 e2,
并且最多包含一个 null 元素。正如其名称所暗示的,此接口模仿了数学上的set 抽象。
在所有构造方法以及 add、equals 和 hashCode 方法的协定上,Set 接口还加入了其他规定,
这些规定超出了从 Collection 接口所继承的内容。出于方便考虑,
它还包括了其他继承方法的声明(这些声明的规范已经专门针对 Set 接口进行了修改,但是没有包含任何其他的规定)。
对这些构造方法的其他规定是(不要奇怪),所有构造方法必须创建一个不包含重复元素的 set(正如上面所定义的)。
如果将可变对象用作 set 元素,那么必须极其小心。如果对象是 set 中某个元素,
以一种影响 equals 比较的方式改变对象的值,那么 set 的行为就是不确定的。
此项禁止的一个特殊情况是不允许某个set 包含其自身作为元素。
某些 set 实现对其所包含的元素有所限制。例如,某些实现禁止 null 元素,而某些则对其元素的类型所有限制。
试图添加不合格的元素会抛出未经检查的异常,通常是 NullPointerException 或 ClassCastException。
试图查询不合格的元素是否存在可能会抛出异常,也可能简单地返回 false;某些实现会采用前一种行为,
而某些则采用后者。概括地说,试图对不合格元素执行操作时,如果完成该操作后不会导致在 set 中插入不合格的元素,
则该操作可能抛出一个异常,也可能成功,这取决于实现的选择。此接口的规范中将这样的异常标记为“可选”。
注意1:Set是一个不包含重复元素的 collection。更正式地说,set 不包含满足 e1.equals(e2) 的元素对 e1 和 e2。
注意2:与List不同的是,在Set中的对象元素不能重复,也就是说你不能把同样的东西两次放入同一个Set容器中。
2.3.1、HashSet
java.util.HashSet类实现了Set 接口,它由哈希表(实际上是一个 HashMap 实例)支持。
更多内容请参考《HashSet》
2.3.2、SortedSet及TreeSet(1.5):
SortedSet是个接口,它里面的中的元素一定是有序的.TreeSet是SortedSet的唯一实现。TreeSet是一个有序的Set,
它用了一种叫红黑树的数据结构【red-black tree data structure】来为元素排序。
这样你就能从Set里面提取一个有序序列了。
TreeSet将放入其中的元素按序存放,这就要求你放入其中的对象是可排序的,
这就用到了集合框架提供的另外两个实用类Comparable和Comparator。一个类是可排序的,它就应该实现Comparable接口。
有时多个类具有相同的排序算法,那就不需要在每分别重复定义相同的排序算法,只要实现Comparator接口即可。
更多详细信息参考《SortedSet和TreeSet》
2.3.3、LinkedHashSet(JDK 1.4):
LinkedHashSet是一个在内部使用链表的Set,既有HashSet的查询速度,又能保存元素被加进去的顺序(插入顺序)。
用Iterator遍历Set的时候,它是按插入顺序进行访问的。
此实现与 HashSet 的不同之外在于,后者维护着一个运行于所有条目的双重链接列表。
更多详细参考《LinkedHashSet》
小结:
HashSet保存对象的顺序是和TreeSet和LinkedHashSet不一样的。这是因为它们是用不同的方法来存储和查找元素的。
TreeSet用了一种叫红黑树的数据结构【red-black tree data structure】来为元素排序,
而HashSet则用了“专为快速查找而设计”的散列函数。LinkedHashSet在内部用散列来提高查询速度,
它只是用链表来保存元素的插入顺序的。
2.3.4、CopyOnWriteArraySet
CopyOnWriteArraySet是对其所有操作使用CopyOnWriteArrayList的 Set。
因此,它共享以下相同的基本属性:
* 它最适合于 set 大小通常保持很小、只读操作远多于可变操作以及需要在遍历期间防止线程间冲突的应用程序。
* 它是线程安全的。
* 因为通常需要复制整个基础数组,所以可变操作(添加、设置、移除,等等)的开销巨大。
* 迭代器不支持可变移除操作。
* 使用迭代器进行遍历的速度很快,并且不会与其他线程发生冲突。在构造迭代器时,迭代器依赖于不变的数组快照。
示例用法。
以下代码使用了一个写时复制(copy-on-write)的 set,以维护在状态更新时执行某项操作的一组 Handler 对象。
class Handler { void handle(); ... }
class X {
private final CopyOnWriteArraySet<Handler> handlers = new CopyOnWriteArraySet<Handler>();
public void addHandler(Handler h) { handlers.add(h); }
private long internalState;
private synchronized void changeState() { internalState = ...; }
public void update() {
changeState();
for (Handler handler : handlers)
handler.handle();
}
}
注意1:CopyOnWriteArraySet是对其所有操作使用CopyOnWriteArrayList的Set。
它共享了CopyOnWriteArrayList的基本属性.
注意2:它是线程安全的。
注意3:感觉CopyOnWriteArraySet和CopyOnWriteArrayList最大的区别就是Set不允许重复的元素。
可能这正是opyOnWriteArraySet存在的意义。
2.3.5、EnumSet(1.5)
EnumSet的本质就为枚举类型定制的一个Set,且枚举set中所有元素都必须来自单个枚举类型。
枚举set中所有元素在内部表示为位向量.此表示形式非常紧凑且高效。此类的空间和时间性能应该很好.
详细见《EnumSet》
2.3.6、JobStateReasons
JobStateReasons 类是打印属性类,它是一个枚举值集合,提供了有关作业当前状态的额外信息,即扩充作业的 JobState 属性值的信息。
注意1:此类在android并没有。所以没有对它的研究。请忽略。
2.4、Map(1.2)
public interface Map<K,V>
将键映射到值的对象。一个映射不能包含重复的键;每个键最多只能映射一个值。
此接口代替 Dictionary 类,后者完全是一个抽象类,而不是一个接口。
Map 接口提供三种collection 视图,允许以键集、值集合或键-值映射关系集的形式查看某个映射的内容。
映射的顺序 定义为迭代器在映射的 collection 视图中返回其元素的顺序。
某些映射实现可明确保证其顺序,如 TreeMap 类;某些映射实现则不保证顺序,如 HashMap 类。
注:将可变对象用作映射键时必须格外小心。当对象是映射中某个键时,如果做了会影响 equals比较的修改,
则映射的行为就不是特定的。此项禁止的一个特殊情况是不允许某个映射包含其自身作为键。
虽然允许某个映射包含其自身作为值,但建议要格外小心:在这样的映射上将无法再定义 equals 和 hashCode 方法。
所有通用的映射实现类应该提供两个“标准的”构造方法:
一个 void(无参数)构造方法,用于创建空映射,
另一个是带有 Map 类型单参数的构造方法,用于创建一个与其参数具有相同键-值映射关系的新映射。
实际上,后一个构造方法允许用户复制任意映射,生成所需类的一个等价映射。尽管无法强制执行该建议(因为接口不能包含构造方法),
但是 JDK 中所有通用的映射实现都遵从它。
该接口中包含的“破坏性”方法可修改其所操作的映射,如果此映射不支持该操作,则指定这些方法抛出 UnsupportedOperationException。
如果是这样,那么在调用对该映射无效时,这些方法可能,但并不一定抛出 UnsupportedOperationException。例如,
如果某个不可修改的映射(其映射关系是“重叠”的)为空,则对该映射调用 putAll(Map) 方法时,可能但并不一定抛出异常。
某些映射实现对可能包含的键和值有所限制。例如,某些实现禁止空键和空值,而某些实现则对其键的类型有限制。
尝试插入不合格的键或值会抛出一个未经检查的异常,
通常是 NullPointerException 或 ClassCastException。
试图查询是否存在不合格的键或值可能抛出异常,或者只是简单地返回 false;
某些实现将表现出前一种行为,而某些实现则表现后一种。较为常见的是,
试图对不合格的键或值执行操作且该操作的完成不会导致不合格的元素被插入映射中时,将可能抛出一个异常,
也可能操作成功,这取决于实现本身。这样的异常在此接口的规范中标记为“可选”。
此接口是 Java Collections Framework 的成员。
Collections Framework 接口中的很多方法是根据 equals 方法定义的。
例如,contains(Object key) 方法的规范声明:
“当且仅当此映射对于键 k 包含以下映射关系时才返回 true:(key==null ? k==null : key.equals(k))”。
不应将此规范解释为它暗指调用具有非空参数 key 的 Map.containsKey 会导致对任意的键 k 调用 key.equals(k)。
可随意对各种实现执行优化,只要避免调用 equals 即可,
例如,通过首先比较两个键的哈希码(Object.hashCode() 规范保证哈希码不相等的两个对象不会相等)。
较为常见的是,各种 Collections Framework 接口的实现可随意利用基础 Object 方法的指定行为,
而不管实现程序认为它是否合适。
Map的功能:
所以从某种意义上讲,它是将数字和对象关联起来。
它就是用另一个对象(键)来查找对象!这是一种至关重要的编程技巧。
这一概念在Java中表现为Map。put(Object key, Object value)方法会往Map里面加一个值,
并且把这个值同键(你查找时所用的对象)联系起来。给出键之后,get(Object key)就会返回与之相关的值。
你也可以用containsKey()和containsValue()测试Map是否包含有某个键或值。
Java标准类库里有好几种 Map:HashMap,TreeMap,LinkedHashMap,WeakHashMap,以及IdentityHashMap。它们都实现了 Map的基本接口,
注意1:Map的本质就是将键映射到值(对象),这里的键也是个对象(本质上是使用它的hashCode())。
2.4.1、HashMap(1.2)
HashMap是基于哈希表的 Map 接口的实现。此实现提供所有可选的映射操作,并允许使用 null 值和 null 键。
(除了不同步和允许使用 null 之外,HashMap 类与 Hashtable 大致相同。)此类不保证映射的顺序,特别是它不保证该顺序恒久不变。
此实现不是同步的。不是线程安全的。
更多请阅读《HashMap》。
2.4.2、SortedMap及TreeMap(1.2)
SortedMap保证按照键的升序排列的映射。TreeMap是SortedMap接口的基于红黑树的实现。
详细见《SortedMap和TreeMap》
2.4.3、LinkedHashMap(1.4)
LinkedHashMap是Map接口的哈希表和链接列表实现,具有可预知的迭代顺序。
此实现与 HashMap 的不同之处在于,后者维护着一个运行于所有条目的双重链接列表。
此链接列表定义了迭代顺序,该迭代顺序通常就是将键插入到映射中的顺序(插入顺序)。
它的映射很适合构建 LRU 缓存。
具体参见《LinkedHashMap》
2.4.4、WeakHashMap(1.2)
WeakHashMap是一个weak key的Map,是为某些特殊问题而设计的。它能让Map释放其所持有的对象。
如果某个对象除了在Map当中充当键之外,在其他地方都没有其reference的话,那它将被当作垃圾回收。
详细内容请参考《WeakHashMap》
2.4.5、IdentityHashMap(JDK 1.4)
IdentityHashMap类利用哈希表实现 Map 接口,比较键(和值)时使用引用相等性代替对象相等性。
换句话说,在 IdentityHashMap 中,当且仅当 (k1==k2) 时,才认为两个键 k1 和 k2 相等(在正常 Map 实现(如 HashMap)中,
当且仅当满足下列条件时才认为两个键 k1 和 k2 相等:(k1==null ? k2==null : e1.equals(e2)))。
2.4.6、ConcurrentMap(1.5)
ConcurrentMap是接口。它提供了putIfAbsent、remove、replace方法的 Map。
定义的接口有:
Public Methods | |
abstract V | putIfAbsent(K key, V value) If the specified key is not already associated with a value, associate it with the given value. 如果指定键已经不再与某个值相关联,则将它与给定值关联。 |
abstract boolean | remove(Object key, Object value) Removes the entry for a key only if currently mapped to a given value. 只有存在给定键到给定对象的条目映射时,才移除该键的条目。 |
abstract boolean | replace(K key, V oldValue, V newValue) Replaces the entry for a key only if currently mapped to a given value. 只有存在给定键到给定对象的条目映射时,才替换该键的条目。 |
abstract V | replace(K key, V value) Replaces the entry for a key only if currently mapped to some value. 只有存在给定键到给定对象的条目映射时,才替换该键的条目。 |
注意1: ConcurrentMap只有一个实现concurrentHashMap。
2.4.7、concurrentHashMap(1.5)
concurrentHashMap是线程安全的,但检索操作不必锁定,不会受阻塞,
因此,可能与更新操作交迭(包括 put 和 remove)。ConcurrentHashMap允许多个修改操作并发进行,其关键在于使用了锁分离技术。它使用了多个锁来控制对hash表的不同部分进行的修改。
通过可选的 concurrencyLevel 构造方法参数(默认值为 16)来设置更新操作之间的并发数。
更多参考《ConcurrentHashMap》和《ConcurrentHashMap实现细节》
2.4.8、EnumMap(1.5)
EnumMap是与枚举类型键一起使用的专用 Map 实现。枚举映射中所有键都必须来自单个枚举类型,该枚举类型在创建映射时显式或隐式地指定。
枚举映射在内部表示为数组。此表示形式非常紧凑且高效。得到元素也很快。
它内部元素是有序的。迭代进行时返回的映射的顺序就是其枚举类型键在枚举声明中的位置顺序。
具体参考《EnumMap》