一、简介
Map接口下存在实现类HashMap、LinkedHashMap(前者的子类)、EnumMap,并有子接口SortedMap,该子接口下有TreeMap。仔细观察可以发现Map接口下的派生类与Set接口下的派生类十分相似,至少从名字上就不难看出。
Map对象中存储的对象以键值对的形式存在,其中key不允许重复,value可以重复。key集合可以理解为一个Set集合,即任何两个key使用equals()
方法比较的结果都为false
。事实上,Map中封装了一个内部类Entry用来封装键值对,而在计算Entry的存储位置时只考虑key。
二、HashMap与Hashtable
这二者的关系类似于ArrayList与Vector的关系。二者的区别如下:
- HashMap线程不安全,Hashtable线程安全.
- HashMap中的key和value可以为null,在Hashtable中无论是key还是value都不允许为null。
判断两个key是否相同的标准是equals()
方法返回true,hashCode
值也相等。与HashSet类似的是,当我们使用引用变量作为key并在之后修改了key时,那么我们遍无法再访问修改过的key所对应的值。
三、性能选项
对于hash类的集合来说,他们都是通过hash算法来计算元素的存储位置(Map中用来决定key的存储位置),并通过hash算法来控制集合的大小。
hash表中存储元素的位置称为“桶”,桶的位置由元素hashCode值决定。通常情况下一个桶中存储一个元素,此时hash表的性能也最好。但发生hash冲突时,一个桶中就会存储多个元素,这些元素按照链表的形式存储。如下图所示:
因为HashSet、HashMap、Hashtable都是用hash算法来决定其元素的存储位置,因此他们的hash表包含以下元素:
- 容量(capacity):hash表中桶的数量。
- 初始化容量(initial capacity):创建表时的桶数量,可以再构造函数中设置。
- 尺寸(size):记录当前表中存储元素的个数。
- 负载因子(load factor):
size/capacity
轻负载的hash表有良好的性能,但是过于为了追求轻负载将hash表的容量设置的过大则会导致内存的浪费。
除此之外hash表中还存在一个负载极限,当负载因子达到负载极限时,hash表会自动扩容,并进行元素的重新分配(rehash)。
四、线程安全
对于Set、List、Map等实现类Java提供了工具类Collections。其中提供了多个synchronizedXxx()
方法用来将集合包装成线程安全的集合。