【Java】集合类 - Map 接口

Posted by 西维蜀黍 on 2019-03-18, Last Modified on 2023-02-28

Map接口

Map接口以按键-值对(key-value)的形式存储数据,这里要特别说明,Map.Entry是Map的内部类,它用来描述Map中一个的键-值对(key-value)。

类图结构

如上图所示是实现Map接口的类图结构,主要包含了如下实现类:

  • HashMap类:HashMap是实现了Map接口的key-value集合,实现了所有map的操作,允许key和value为null,它相当于Hashtable,与之存在的区别是hashMap不是线程安全的,HashMap允许null值。

  • TreeMap类:TreeMap是基于红黑树的实现,也是记录了key-value的映射关系,该映射根据key的自然排序进行排序或者根据构造方法中传入的比较器进行排序,也就是说TreeMap是有序的key-value集合

  • Hashtable类:它是类似与HashMap的key-value的哈希表,不允许key-value为NULL值,另外一点值得注意的是Hashtable是线程安全的

实现

  • HashMap:实现了Map接口,继承了AbstractMap类
  • Hashtable:实现了Map接口,继承了AbstractMap类
  • TreeMap:由于TreeMap是有序的,所以其除了实现了Map接口,还实现了SortedMap、NavigableMap接口
  • LinkedHashMap

内部原理

  • HashMap:HashMap是散列表实现,内部是数组+链表或者红黑树的结构
  • Hashtable:Hashtable也是散列表实现,内部是数组+链表的结构
  • TreeMap:TreeMap内部是红黑树的结构

线程安全

  • HashMap:不是线程安全的,其实通过Map m = Collections.synchronizeMap(hashMap)的方式也可以使得HashMap变成线程安全的,但是这样做对程序的性能可能是噩梦,在后面会介绍ConcurrentHashMap,建议在多线程的情况下可以使用ConcurrentHashMap替换HashMap.
  • Hashtable:是线程安全的,内部方法使用关键字synchronized修饰
  • TreeMap:不是线程安全的

遍历Map

迭代 Map中的元素不存在直接的方法。如果要查询某个 Map以了解其哪些元素满足特定查询,或如果要迭代其所有元素,则你必须首先获取该 Map的“视图”。共有三种视图。

以下是返回视图的 Map方法。通过使用这些方法返回的对象,可以遍历 Map中的元素,也可以删除 Map中的元素。

entrySet()

返回 Map中所包含映射的 Set视图。 Set 中的每个元素都是一个 Map.Entry对象,可以使用 getKey()和 getValue()方法(还有一个 setValue()方法)访问后者的键元素和值元素。

keySet()

返回 Map中所包含键的 Set 视图。删除 Set中的元素还将删除 Map中相应的映射(键和值)。

values()

返回 map中所包含值的 Collection视图。删除 Collection中的元素还将删除 Map中相应的映射(键和值)。

HashMap

HashMap是最常用的Map,它根据键的hashCode值存储数据,根据键可以直接获取它的值,具有很快的访问速度,遍历时,取得数据的顺序是完全随机的。因为键对象不可以重复,所以HashMap最多只允许一条记录的键为Null,允许多条记录的值为Null,是非同步的

Hashtable

Hashtable与HashMap类似,是HashMap的线程安全版,它支持线程的同步,即任一时刻只有一个线程能写Hashtable,因此也导致了Hashtale在写入时会比较慢,它继承自Dictionary类,不同的是它不允许记录的键或者值为null,同时效率较低。

ConcurrentHashMap

线程安全,并且锁分离。ConcurrentHashMap内部使用段(Segment)来表示这些不同的部分,每个段其实就是一个小的hash table,它们有自己的锁。只要多个修改操作发生在不同的段上,它们就可以并发进行。

LinkedHashMap

LinkedHashMap保存了记录的插入顺序,在用Iteraor遍历LinkedHashMap时,先得到的记录肯定是先插入的,在遍历的时候会比HashMap慢,有HashMap的全部特性。

TreeMap

TreeMap实现SortMap接口,能够把它保存的记录根据键排序,默认是按键值的升序排序(自然顺序),也可以指定排序的比较器,当用Iterator遍历TreeMap时,得到的记录是排过序的。不允许key值为空,非同步的。

Reference