双列集合
常见双列集合体系如下图:
-
Map接口
-
存储Key-Value对的双列数据;
- HashMap
作为Map接口的主要实现类,线程不安全,但效率高;可以存储null的key和value;
底层实现:JDK7及以前(数组+链表);JDK8(数组+链表+红黑树)- LinkedHashMap
HashMap子类,可以按照添加元素顺序遍历该集合元素,因为:其在原有的HashMap底层上添加以一对引用,指向前一 个和后一个元素,当有频繁的遍历操作时,使用此集合效率高
- LinkedHashMap
- Hashtable
作为古老的实现类,线程安全但效率低;不能存储null的key和value- Properties
常用来处理配置文件,key和value都为Sring类型;
存取数据时,一般用setProperty(String key,String value)和getProperty(String key)方法
- Properties
- SortedMap接口(少用)
- TreeMap
保证按照添加的key-value对进行排序,实现排序遍历;其底层使用的是红黑树;
- HashMap
-
Map结构的理解:
Map的key:无序不可重复,使用Set存储所有的key【key所在的类要重写hashCode和equals方法】
Map的value:无序可重复,使用Collection存储所有的value【value所在的类要重写equal方法】
一个键值对:无序不可重复,一个key-value构成了一个Entry对象;
Map中的entry:无序不可重复的,使用Set存储所有的entry; -
Map中定义的方法:
添加、删除、修改操作:
Object put(Object key,Object value):将指定key-value添加到(或修改)当前Map对象中;
void putAll(Map m):将m中的所有key-value对存放到当前map中;
Object remove(Object key):移除指定key的key-value对,并返回value;
void clear():清空当前Map中的所有数据
元素查询的操作:
Object get(Object key):获取指定key对应的value;
boolean containsKey(Object key):是否包含指定的key;
boolean containsValue(Object value):是否包含指定的value;
int size():返回map中key-value对的个数;
boolean isEmpty():判断当前map是否为空;
boolean equals(Object obj):判断当前map和参数对象obj是否相等;
元视图操作的方法:
Set keySet():返回所有key构成的Set集合;
Collection values():返回所有value构成的Collection集合;
Set entrySet():返回所有key-value对构成的Set集合;
常用方法:
添加:put(Object key,Object value)
删除:remove(Object key)
修改:put(Object key,Object value)
查询:get(Object key)
长度:size()
遍历:keySet() / values() / entrySet() -
HashMap的底层(JDK7为例):
-
源码中重要标识符及其值:
DEFAULT_INITAL_CAPACITY:HashMap的默认初始容量(16)
DEFAULT_LOAD_FACTOR:默认的加载因子(0.75)
threshold:扩容临界值=默认初始容量加载因子(160.75=12)
TREEIFY_THRESHOLD:Bucket(桶)中链表长度大于该默认值(8),则转化为红黑树
MIN_TREEIFY_CAPACITY:Bucket中Node被树化时最小的hash表(数组)容量(64) -
实现原理:
HashMap map = new HashMap();
在创建对象之后,HashMap会创建一个长度为16的数组【Entry table[]】;
…可能已经多次put操作…
put(key1,value1);
首先,调用key所在的类的hashCode方法计算出key的hash值,再通过某种算法计算出该key要存储的数 组索引:
1)若该索引位置没有元素,则添加成功【情况1】;
2)若该索引位置有一个或多个元素(链表形式存在),则分别比较这些元素的哈希值:
|— 若与所有元素哈希值不同则添加成功【情况2】;
|— 若与其中一个元素哈希值相同,则调用key所在类的equals方法,
若返回false,则添加成功【情况 3】,若返回true,则用新的value1替换原来的value;声明一:关于【情况2】和【情况3】,新的key1-value1与原来的数据以链表形式存储;
声明二:在不断添加过程中会涉及到扩容问题,当超出临界值【默认threshold】时,
集合容量会扩大到原来两倍,并将原有的数据复制过来;
-
-
LinkedHashMap的底层实现原理
源码中:
-
static class Entry<K,V> extends HashMap.Node<K,V> { Entry<K,V> before, after;//能够记录添加的元素的先后顺序 Entry(int hash, K key, V value, Node<K,V> next) { super(hash, key, value, next); }
- JDK8 相较于JDK7在底层实现方面的不同:
1)当new HashMap()时,底层没有创建一个长度为16的数组;
2)JDK8中底层的数组是Node[],而不是Entry[]
3)在第一次调用put方法时,才创建了一个长度为16的数组
4)JDK7底层的数据结构【数组+链表】与JDK8中【数组+链表+红黑树】不同
4.1) 形成链表时,七上八下(jdk7:新的元素指向旧的元素。jdk8:旧的元素指向新的元素)
4.2)当数组的某一个索引位置上的元素以链表形式存在的数据个数 > 8 且当前数组的长度 > 64时,此时此索引位置上的所数据改为使用红黑树存储