JDK Map
Map接口中的方法
- 判断系。
containsKey
包含元素、containsValue
包含值、isEmpty
是否为空。 - 读取系。
size
大小、get
获取元素 - 增删系。
put
增加、remove
删除、putAll
增加所有、clear
清空。 - 转化系。
entrySet
返回键值对、、keySet
返回键集合、values
返回值集合。
Map下面的抽象类与接口
- AbstractMap
AbstractMap
中包含两个键值对类,SimpleImmutableEntry
与SimpleEntry
前者初始化之后,不可修改值,后面不是。 简单实现了Map
接口中的方法, - ConcurrentMap
ConcurrentMap
中增加了两个替换replace
、一个如果没有就设置putIfAbsent
、一个移除键值remove
四个方法。主要实现类为ConcurrentHashMap
。 - SortedMap
SortedMap
排序的Map,增加了头keyfirstKey
,尾keylastKey
,切片方法headMap
、tailMap
、subMap
、还有一个比较器comparator
。 - NavigableMap
SortedMap
子接口,新增一系列Navigable
的方法,能访问有序Map中的第一个、最后一个、返回比入参大,入参小的等等,这里不细说。 - ConcurrentNavigableMap ConcurrentMap与NavigableMap的接合。
Map中的内部类
Cellections
中,SynchronizedSortedMap
、SynchronizedMap
、CheckedSortedMap
、CheckedMap
、EmptyMap
。在JDK中集合的辅助类中已经说过。ConcurrentSkipListMap
中的SubMap
。ConcurrentSkipListMap
的分段类TreeMap
中的AscendingSubMap
、DescendingSubMap
。分段类,升序与降序两种。
HashMap
内部原理
HashMap
内部数据结果是数组+链表。 根据map的key的hash值,进行一系列的算法,最后模得数组中的下标,如果下标链表中有实体里,那就把这个元素放到链表的最前面。 数组大小是固定,所以需要动态扩容,是扩容却不是动态定内部数组大小,所以如果先放大,最后删除,但是数组大小不会缩小。 可以看到HashMap
对null
的key与value都有处理。
动态配置初始化大小
内部静态类Holder
中可以配置初始化数组的大小jdk.map.althashing.threshold
。
modCount的作用
和ArrayList
一样,HashMap
中也有modCount字段,同样的作用。
逃脱
因为是HashMap
,所以元素放到map中的位置与对象的hash有关,所以在对象改变了hash值,就算对象引用没有变,也会每次放到不同的位置,换句话说,一个对象可以放在同一个map的不同位置。
public class Mappest { public int id; public String name; public Mappest(int id, String name) { this.id = id; this.name = name; } @Override public int hashCode() { return id + name.hashCode(); } @Override public boolean equals(Object obj) { if(!(obj instanceof Mappest)){ return false; } Mappest m2 = (Mappest) obj; if(this.hashCode() == m2.hashCode()){ return true; } return false; } public static void main(String[] args) { HashMapmap = new HashMap<>(); Mappest mada = new Mappest(1, "mada"); map.put(mada, "1"); mada.id = 2; map.put(mada, "2"); for (Map.Entry en : map.entrySet()) { System.out.println(en.getValue()); } }}
HashTable
内部原理
HashMap
的同步版本,synchronized
同步方法。内部原理与HashMap
类似。
TreeMap
内部原理
实现了NavigableMap
接口。对外提供已排序的数组,内部使用的是红黑树结构(详细见这片)。 实例化TreeMap
两种情况,一是Map元素实现java.lang.Comparable
,二是java.util.Comparator
比较器。
modCount
好吧,TreeMap中也有这个东东,作用类型。
AscendingSubMap与DescendingSubMap
AscendingSubMap
与DescendingSubMap
表示升序,降序子Map。这里的升序是针对Comparable
或Comparator
而言,所以降序也只是反序Comparable
或Comparator
。 红黑树所有结点是有序存储。是升序,降序是对迭代顺序的。TreeMap
是正序,所以在DescendingSubMap
中,使用了Collections中的reverseOrder
方法。
WeakHashMap
HashMap的WeakReference版本,WeakHashMap
内部维护一个ReferenceQueue<Object>
的数组,内部Entry
继承WeakReference<Object>
,通过WeakReference与ReferenceQueue配合实现了弱引用缓存,可以看这篇
LinkedHashMap
LinkedHashMap
继承HashMap
。内部使用HashMap
储存数据,但是同时维持一个双向链表,用于记录访问顺序。 如果accessOrder为true。访问get
方法,也会调整顺序:将被访问的元素,挪到顺序链表的表尾。
Properties
Properties
继承Hashtable
。用于读取properties文本。 借助XMLUtils
读取xml
文件。
EnumMap
枚举Map,Key只能是传入的枚举类实例。内部使用数组存储数据,而存取元素下标是枚举元素的ordinal
,这样就没有下标计算过程,效率更高。
public V put(K key, V value) { typeCheck(key); int index = key.ordinal(); Object oldValue = vals[index]; vals[index] = maskNull(value); if (oldValue == null) size++; return unmaskNull(oldValue);}
同样,也没有逃逸的问题。
IdentityHashMap
IdentityHashMap
的内部结构与HashMap
内部结构不同。
- 前者使用数组存储,后者使用数组+链表。
- 前者使用key相同(==),后者是相等(equal)。这样就不存在HashMap中逃脱的情节。
- 前者的下标如果存在实体,就会往下找一个有两个空的下标,将相同的两个实体都放入。
ConcurrentHashMap
ConcurrentHashMap
内部将所有数据放到Segment
数组中,而Segment
中有HashEntry
数组。所以是数组+数组
格式。 Segment
继承ReentrantLock
,与HashTable
不同,ConcurrentHashMap
的锁对象不是整个Map,而是Segment
。
ConcurrentSkipListMap
TreeMap的同步版本。