Java集合源码分析07----Map集合

目录

 

Map集合综述

Map接口

SortedMap接口

NavigableMap接口

Dictionary抽象类

AbstractMap抽象类

总结

————————–分析基于jdk1.8.

Map集合综述

    Map接口是Map继承体系中的根接口,与Collection集合没有必然的联系。Map集合存储的是键-值映射(键-值对)。在Map中键与值是一一对应的,也就是一个键只对应一个值。所以不能存在相同的键,值是可以一样的。因此来通过键来查找值。常见的Map实现类有TreeMap,HashMap,IdentityHashMap,WeakHashMap,Hashtable,LinkedHashMap等。

    其中抽象类AbstractMap继承接口Map,实现了Map接口中大部分的方法,而Map的大部分的实现类都直接继承了AbstractMap,这样节省了实现类大部分了重复的代码。

《Java集合源码分析07----Map集合》

Map接口

    Map提供的是键与值的映射关系,Map中不能包含重复的键,每个键最多有一个值。Map接口出现是为了替换抽象类Dictionary。

    Map接口提供了三种集合Collection视图:键集合值集合键-值映射集合。映射的顺序就是映射集合视图上迭代器返回元素的顺序,有些实现类能确保顺序,比如TreeMap。有些实现类不能保证顺序,如HashMap。

    需要注意的是:将可变的对象作为映射键时要小心,比如键不能是Map类型,但是值可以是Map类型。

//返回Map中键值对映射的数量.
int size();
//如果Map不包含任何的键值对映射,返回true.
boolean isEmpty();
//如果Map中存在指定的键key,返回true.
boolean containsKey(Object key);
//如果Map包含指定的值value,返回true.
boolean containsValue(Object value);
//返回指定的键所映射的值.
V get(Object key);
//将键与对应的值映射关系插入到Map中.
V put(K key, V value);
//从Map中移除键的映射关系.
V remove(Object key);
//批量操作
//将指定的Map中所有映射关系添加此映射中.
void putAll(Map<? extends K, ? extends V> m);
//从Map中移除所有的映射关系.
void clear();
//视图查看
//返回此Map中所有键的Set视图.
Set<K> keySet();
//返回所有包含在Map中所有值的Collection视图.
Collection<V> values();
//返回此Map中键值映射关系的Set视图.
Set<Map.Entry<K, V>> entrySet();
//此Map是否与指定的对象相等.
boolean equals(Object o);
//返回此Map的HashCode值.
int hashCode();
//返回Map中与key关联的值,如果在映射中没有找到此键,将返回defaultValue.
default V getOrDefault(Object key, V defaultValue) {}
//对这个Map中所有的键/值执行action.
default void forEach(BiConsumer<? super K, ? super V> action) {}
//用键值对在给指定函数上的执行结果替换键值对的值.
default void replaceAll(BiFunction<? super K, ? super V, ? extends V> function) {}
//键没有映射关系情况下与指定的值进行关联.
default V putIfAbsent(K key, V value) {}
//当指定的key与指定值value关联的情况下,移除键值对.
default boolean remove(Object key, Object value) {}
//当key与oldValue关联情况下,用newValue替换oldValue与key进行关联.
default boolean replace(K key, V oldValue, V newValue) {}
//Map中存在key的映射关系时,将key与value进行关联.返回key之前关联的值
default V replace(K key, V value) {}
//如果指定key不存在映射关系,根据key计算出的函数值,将key与函数值进行关联.
default V computeIfAbsent(K key,Function<? super K, ? extends V> mappingFunction) {}
//如果键对应的值存在且非空,根据key和key映射的值计算出的函数值,函数值不为空时,将key与函数值关联.
default V computeIfPresent(K key,BiFunction<? super K, ? super V, ? extends V> remappingFunction) {}
//与computeIfPresent区别是,key不存在映射时,并且函数值不为null时,会将key与函数值进行关联.
default V compute(K key,BiFunction<? super K, ? super V, ? extends V> remappingFunction) {}
//如key不存在映射时,指定value不为null时,将key与value关联,
//否则key的映射值与指定值value的函数值不为null时,将key与函数值关联
default V merge(K key, V value,BiFunction<? super V, ? super V, ? extends V> remappingFunction) {}

SortedMap接口

SortedMap直接继承了Map接口,是有序的键-值映射(针对键进行排序)。

SortedMap的排序方式是通过键的自然顺序或者创建SortedMap时指定的Comparator。在键集,值集,键-值映射集迭代时将会体现出这种排序。插入SortedMap中的所有键都必须实现Comparable接口(或被指定比较器接受)。

所有SortedMap的实现类都应该提供4个标准的构造方法(建议但不强制):

1)无参构造方法:创建的是空的有序映射,按照键的自然序进行排序。

2)指定Comparator类型参数的构造方法:创建的是空的有序映射,根据指定Comparator进行排序。

3)带有Map类型参数的有参构造方法:创建一个与参数Map相同的键-值映射关系的有序映射。按照键的自然顺序进行排序。

4)带有SortedMap类型参数的有参构造方法:创建一个与参数SortedMap相同的键-值关系的和排序的有序映射。

//返回对此映射进行排序的Comparator对象,映射使用键的自然序时,将返回null.
Comparator<? super K> comparator();
//返回此映射的部分视图,其键值的方位从fromKey(包含)到toKey(不包含)
SortedMap<K,V> subMap(K fromKey, K toKey);
//返回此映射中键值小于toKey(不包含)的部分视图
SortedMap<K,V> headMap(K toKey);
//返回此映射中键值大于等于fromKey的部分视图.
SortedMap<K,V> tailMap(K fromKey);
//返回映射中的第一个键
K firstKey();
//返回映射中的最后一个键
K lastKey();
//返回映射中的键集合.
Set<K> keySet();
//返回映射中的值集合
Collection<V> values();
//返回映射中键-值映射集合
Set<Map.Entry<K, V>> entrySet();

NavigableMap接口

NavigableMap接口继承自SortedMap,具有针对搜索目标返回最接近匹配项的导航方法,可以通过键的升序和降序访问和遍历NavigableMap.Navigable接口包含了以下几类方法:

1)获取指定范围的键-值映射(对)的方法:

     lowerEntry、floorEntry、ceilingEntry 和 higherEntry 方法,分别返回与小于、小于等于、大于等于、大于给定键的键关联的 Map.Entry 对象。

2)操作指定的键-值映射(对)的方法:

    firstEntry、pollFirstEntry、lastEntry 和 pollLastEntry 方法,返回和/或移除最小和最大的映射关系(如果存在),否则返回 null。

3)获取指定的键的方法:

   lowerKey、floorKey、ceilingKey 和 higherKey 方法,分别返回与小于、小于等于、大于等于、大于给定键的键。

4)查看键-值的部分视图:

subMap(K fromKey, K toKey)/subMap(K fromKey, boolean fromInclusive,K toKey,boolean toInclusive)、headMap(K toKey)/headMap(K toKey, boolean inclusive)、tailMap(K fromKey)/subMap(K fromKey, K toKey)方法,分别返回fromKey到toKey之间(设置是否包含),小于或者等于(设置是否包含)toKey,大于或者等于(设置是否包含)toKey的键-值视图。

5)正逆序的键集/键-值集映射:

navigableKeySet、descendingKeySet、descendingMap方法,分别是正序键集、逆序键集,以及逆序键-值映射。

//返回小于指定键的最大键对应的键-值映射,如果不存在这样的键,返回null
Map.Entry<K,V> lowerEntry(K key);
//返回小于指定键的最大键,如果不存在这样的键,返回null.
K lowerKey(K key);
//返回小于等于指定键的最大键对应的键-值映射,如果不存在这样的键,返回null.
Map.Entry<K,V> floorEntry(K key);
//返回小于等于指定键的最大键,如果不存在这样的键,返回null.
K floorKey(K key);
//返回大于等于指定键的最小键对应的键-值映射,如果不存在这样的键,返回null.
Map.Entry<K,V> ceilingEntry(K key);
//返回大于等于指定键的最小键,如果不存在这样的键,返回null.
K ceilingKey(K key);
//返回大于指定键的最小键对应的键-值映射,如果不存在这样的键,返回null.
Map.Entry<K,V> higherEntry(K key);
//返回大于指定键的最小键,如果不存在这样的键,返回null.
K higherKey(K key);
//返回最小键对应的键-值映射,如果map为空,返回null.
Map.Entry<K,V> firstEntry();
//返回最大键对应的键-值映射,如果map为空,返回null.
Map.Entry<K,V> lastEntry();
//移除并返回最小键对应的键-值映射,如果map为空,返回null.
Map.Entry<K,V> pollFirstEntry();
//移除并返回最大键对应的键-值映射,如果map为空,返回null.
Map.Entry<K,V> pollLastEntry();
//返回map中键-值逆序的视图.
NavigableMap<K,V> descendingMap();
//返回map中所有键的NavigableSet视图。
NavigableSet<K> navigableKeySet();
//返回map中所有键的逆序的NavigableSet视图.
NavigableSet<K> descendingKeySet();
//返回从fromkey到tokey之间的map的部分视图,并且分别指定了是否fromkey和tokey
NavigableMap<K,V> subMap(K fromKey, boolean fromInclusive,K toKey,boolean toInclusive);
//返回小于或者等于(由inclusive指定,true时包含)tokey的map的部分视图.
NavigableMap<K,V> headMap(K toKey, boolean inclusive);
//返回大于或者等于(由inclusive指定,true时包含)tokey的map的部分视图.
NavigableMap<K,V> tailMap(K fromKey, boolean inclusive);
//等价于subMap(fromKey, true, toKey, false)
SortedMap<K,V> subMap(K fromKey, K toKey);
//等价于headMap(toKey, false)
SortedMap<K,V> headMap(K toKey);
//等价于tailMap(fromKey, true)
SortedMap<K,V> tailMap(K fromKey);

Dictionary抽象类

Dictionary是一些类的抽象父类,比如Hashtable,存储的是键-值映射关系。每个键最多与一个值关联。

需要注意的是:Dictionary已经过时,新实现的类应该继承Map接口。

//返回此Dictionary中键值对数量
abstract public int size();
//如果此Dictionary中不存在键-值对映射,返回true.
abstract public boolean isEmpty();
//返回遍历Dictionary键的Enumeration
abstract public Enumeration<K> keys();
//返回遍历Dictionary值的Enumeration
abstract public Enumeration<V> elements();
//返回此Dictionary中指定键对应的值
abstract public V get(Object key);
//将指定键和指定值映射添加到Dictionary
abstract public V put(K key, V value);
//从Dictionary中移除指定键对应键-值映射
abstract public V remove(Object key);

AbstractMap抽象类

AbstractMap抽象类提供了Map接口大部分实现,减少了Map实现类的重复代码。大部分的实现类如TreeMap,HashMap,IdentityHashMap,WeakHashMap,Hashtable,LinkedHashMap直接继承AbstractMap抽象类。

//返回键集的大小
public int size() {}
//返回键集是否为空
public boolean isEmpty() {}
//如果映射map中包含指定的值,返回true.
public boolean containsValue(Object value) {}
//如果映射map中包含键,返回true.
public boolean containsKey(Object key) {}
//返回指定键对应的值
public V get(Object key) {}
//将指定的键-值映射添加到此map中
public V put(K key, V value) {}
//从此map中移除指定的键对应的键-值映射
public V remove(Object key) {}
//将指定的映射集添加到此映射map中
public void putAll(Map<? extends K, ? extends V> m) {}
//清空键集,底层调用entrySet().clear()
public void clear() {}
//返回此map的键集
public Set<K> keySet() {}
//返回此map的值集
public Collection<V> values() {}
//此map是否与指定对象相等
public boolean equals(Object o) {}
//返回此map的hashCode值
public int hashCode() {}
//map的字符串表示
public String toString() {}
//返回AbstractMap实例的浅度复制
protected Object clone() {}

关于AbstractMap的几个实现类说明:

1)TreeMap:底层以红黑数实现,是一个有序的键-值集合,不是同步的。存入TreeMap中元素要实现Comparable接口,可以通过两种方式对元素进行排序:第一种是自然顺序,第二种是创建TreeMap时指定Comparator比较器。是一种带有subMap()方法的Map,返回键-值映射集的子视图。

2)HashMap:取代了Hashtable,底层以散列表(哈希表)数据结构实现(数组+链表),内部定义了一个数组,计算元素的哈希地址转换成存放的索引,如果有冲突,使用散列链表的形式(单链表),将相同的哈希值的元素串起来。插入和查询键值对的开销固定,可以通过构造器设置容量和负载因子,以调整容器的性能。

3)LinkedHashMap:是HashMap的子类,获取键值对的顺序是其插入的次序或者是最近最少使用(LRU)的次序,底层以散列表(哈希表)实现(数组+链表),并且不是同步的,多个线程访问时,需要进行外部同步。LinkedHashMap允许存储null值和null键。与HashMap相比,使用双向链表来维护内部元素的顺序,所以迭代访问速度较快

4)IdentityHashMap:底层以散列表(哈希表)数据结构实现(数组+链表),但是键的散列值不是通过hashCode函数计算的,而是通过System.identityHashCode方法计算的,这是Object.hashCode方法根据对象的内存地址来计算散列码时使用的方法。比较键(和值)时使用的是引用相等,而不是对象的相等性。也就是比较是不是同一个对象,在代码里面比较的是”==”,而不是equals。

5)WeakHashMap:底层数据结构与HashMap是一致的,以散列表(哈希表)实现(数组+链表),键和值都可以是null。当WeakHashMap中某个键不再正常使用时,会被移除。对于给定的键,即使存在映射关系并不阻止垃圾回收器对键的回收。

6)EnumMap:是一个键为枚举类型的映射,底层是对象数组,数组的下表索引是根据Map中key直接获取的,即枚举中ordinal值。

不是继承AbstractMap的Map实现类:

7)Hashtable:底层数据结构与HashMap是一致的,以散列表(哈希表)实现(数组+链表),键和值不能是null,Hashtable是同步的(线程 安全)。

总结

1)当在Map键集视图上调用迭代器remove方法时,实际上回在Map删除这个键对应的值。但在键集上使用add方法会抛出UnsupportedOperationException异常。

2)HashMap,IdentityHashMap,LinkedHashMap等映射集底层都是以散列表(哈希表)实现的。java中散列表是通过数组+链表的形式实现的,每个散列表称为桶(bucket),查找散列表中指定对象的位置,就需要计算对象的散列码,然后与桶总数取余数,所得到的结果就是保存这个对象在桶中的索引。如果在桶中已经存在对象,就将要入存入对象和已存在的对象串起来(从链表的头部插入),在桶中存储的每一项就是一个链表。

3)当存储在映射集中的元素自己实现hashCode方法时,需要与equals方法兼容。如果a.equals(b)为true时,a与b必须有相同的散列码。Java中对于equals方法与hashCode方法规定:a.相等(相同)的对象必须有相同的散列码(哈希码);b.两个对象的hashCode相同,它们并不一定是同一个对象。

    原文作者:java集合源码分析
    原文地址: https://blog.csdn.net/lili13897741554/article/details/83786611
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞