Java集合之Map接口

Map与List、Set接口不同,它是由一系列键值对组成的集合,提供了key到Value的映射。同时它也没有继承Collection。在Map中它保证了key与value之间的一一对应关系。也就是说一个key对应一个value,所以它不能存在相同的key值,当然value值可以相同。

Map接口体系

Map接口

Map接口提供了一系列操作键值对的方法,并且将键值对抽象为独立的对象,提供键值对维度的操作。

Map< K,V >接口
键值对映射

  • clear() 清空map
  • Java8 新增加compute(K key, BiFunction< ? super K, ? super V, ? extends V> remappingFunction) 对map中key为对应k的value进行对应的函数式操作
  • Java8 新增加computeIfAbsent(K key, Function< ? super K, ? extends V> mappingFunction) 当map中不存在key时,进行函数式操作,并将结果作为value,K作为key,放入map
  • Java8 新增加computeIfPresent(K key, BiFunction< ? super K, ? super V,? extends V> remappingFunction)当map中存在key时,进行函数式操作,并将结果作为value,K作为key,更新对应的key-value
  • containsKey(Object key) 是否包含对应的key
  • containsValue(Object value) 是否包含对应的value
  • entrySet() 返回map的Map.Entry< K,V >的Set
  • Java8 新增加 forEach(BiConsumer< ? super K, ? super V> action) 为每个Map包含的entry执行对应的二元函数式运算(BiConsumer表示二元函数式接口)
  • get(Object key) 获取key对应的value
  • getOrDefault(Object key, V defaultValue)获取key对应的value,没有对应的key返回defaultValue
  • isEmpty() Map是否为空
  • keySet() 返回Map的Key的集合(Set)
  • Java8 新增加merge(K key, V value, BiFunction< ? super V, ? super V, ? extends V> remappingFunction)当map中不存在key时,进行函数式操作,并将结果作为value,K作为key,放入map
  • put(K key, V value) 将一个键值对放入map
    - putAll(Map< ? extends K,? extends V> m) 将一个子map放入当前map
    - putIfAbsent(K key, V value) 仅当map中不存在对应的k-v时,将键值对放入map
    - remove(Object key) 移除对应的k-v
    - remove(Object key, Object value) 移除对应的k-v
    - replace(K key, V value) 替换对应key的value
    - replace(K key, V oldValue, V newValue) 替换对应的k-v的value
    - replaceAll(BiFunction< ? super K, ? super V, ? extends V> function) 对每个键值对执行对应的二元函数式运算,并用运算结果替代value
    - size() 返回map的keySet的size
    - values() 返回map的value的集合

Map内部接口Entry,由于是内部接口,所以Entry默认是静态的,只能访问Map的静态成员变量。

Map.Entry接口

Map.Entry< K,V > 接口
键值对对象

  • getKey() 获取键值对的key
  • getValue() 获取键值对的value
  • setValue(V value) 替换键值对的value
  • comparingByKey() 返回Map的key的比较器
  • comparingByKey(Comparator< ? super K> cmp) 返回一个key的cmp比较器
  • comparingByValue() 返回map的value的比较器
    comparingByValue(Comparator< ? super V> cmp) 返回一个value的cmp比较器

HashMap< K , V>

HashMap is implemented as a hash table, and there is no ordering on keys or values.


HashMap doesn't allow two identical elements. By default, the hashCode() and equals() methods implemented in the Object class are used. The default hashCode() method gives distinct integers for distinct objects, and the equals() method only returns true when two references refer to the same object.

HashMap是哈希表的一种实现,其内部是无序的,元素的存储位置由其哈希值决定。
HashMap的键不允许相同,如果使用继承了Object的类作为键值,需要重写equals方法,因为Object类的equals方法只有当两个引用指向同一个对象时才返回true,不从写equals方法可能导致无法预知的错误。
HashMap继承AbstractMap,AbstractMap类是Map接口的最小实现类。
HashMap的key和value都能为null。
Java8中,当HashMap底层数组的某个链表过大时(长度大于8),会将这部分节点转化为TreeNode结构存储。详细了解可参考:http://blog.163.com/he_04143164/blog/static/27150310320173293218939/。
HashMap是线程不安全的,多线程时使用CurrentHashMap,CurrentHashMap详细解析请参考后续java.util.current包系列文章。
可以用Collections.synchronizedMap保证线程安全
Map m = Collections.synchronizedMap(new HashMap(...));
HashMap类
HashMap方法基本都是对于Map接口的实现,没有额外的新增方法。

HashMap原理:
HashMap的键值对类Node实现了Map接口的Map.Entry接口,Node是一种单向链表,它有一个next属性指向下一个节点。
Node节点以数组的形式存储,entry的hash值决定它的存储位置,如果当前位置还有其他的entry,则用链表存储。如图:
HashMap内部存储结构

TreeMap< K , V>

TreeMaps are sorted by keys, the object for key has to be able to compare with each other, that's why it has to implement Comparable interface.

TreeMap内部存储是根据key值排序的,所以key的对象必须实现Comparable 接口。

TreeMap实现了SortedMap< K,V >接口,SortedMap提供了基于key的排序功能。
SortedMap< K,V > 接口
key是按照自然顺序排序的(或者按照比较器排序)
comparator() 返回有序map的比较器
entrySet() 返回有序map的Entry集合
firstKey() 返回有序map的第一个key
headMap(K toKey) 返回toKey之前的子map
keySet() 返回有序map的key的集合
lastKey() 返回有序map的最后一个key
subMap(K fromKey, K toKey) 返回有序map从fromKey到toKey的子map,包括fromKey,不包括toKey
tailMap(K fromKey) 返回fromKey开始的子map,包括fromKey
values() 返回map的value的集合

TreeMap的内部是一颗红黑树,红黑树原理比较复杂,具体分析可参考:http://www.importnew.com/19074.html。

Hashtable< K , V>
基本和HashMap没有区别,除了所有的方法都加了synchronized关键字保证线程安全和不允许插入null之外(key和value都不能为null)。

LinkedHashMap< K , V>
HashMap的子类,继承了HashMap的方法和特性,同时可以保证元素的插入顺序,即当插入A,B,C时,迭代器得到的的顺序也是A,B,C.

LinkedHashMap的内部节点Entry继承自HashMap.Node,额外新增加了Entry< K,V > before, after两个属性。before和after就是为了记录前一个插入的元素和记录后一个插入的元素。

[1]: HashMap源码分析
[2]: LinkedHashMap源码详解

posted on 2018-11-21 17:47  ShoolyShooly  阅读(177)  评论(0编辑  收藏  举报

导航