一、
public class HashMap extends AbstractMap
implements Map, Cloneable, Serializable {
//数组的默认初始化容量为:16
static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // aka 16
//数组的最大扩容到:2的30次方
static final int MAXIMUM_CAPACITY = 1 << 30;
//默认的扩容因子0.75
static final float DEFAULT_LOAD_FACTOR = 0.75f;
//当链表上节点数大于8时,将链表转为红黑树----因为链表节点数大于8时,会影响其查询效率
static final int TREEIFY_THRESHOLD = 8;
//当红黑树上节点数小于6时,将红黑树转为链表
static final int UNTREEIFY_THRESHOLD = 6;
//存储节点元素的数组
transient Node[] table;
//数组元素个数
transient int size;
//每次扩容和更改map结构的次数
transient int modCount;
//需要扩容的临界值:当大于(初始化容量*0.75)【临界值时】,以2倍进行扩容
int threshold;
}
static class Node implements Map.Entry {
final int hash; // 哈希值
final K key; // 键
V value; // 值
Node next; // 下一个节点地址
}
//计算哈希值 = key(键).hashCoder()
putVal(hash(key), key, value, false, true);
//核心代码
final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
boolean evict) {
Node[] tab; Node p; int n, i;
if ((tab = table) == null || (n = tab.length) == 0)
//可以对数组进行初始化和扩容操作
n = (tab = resize()).length;
//通过(n - 1) & hash找到所在数组相应位置
if ((p = tab[i = (n - 1) & hash]) == null)
tab[i] = newNode(hash, key, value, null);
else {
Node e; K k;
//当hash值和key都相等时,会将链表中第一个元素(数组中的结点)的内容进行覆盖
if (p.hash == hash &&
((k = p.key) == key || (key != null && key.equals(k))))
e = p; //内容覆盖
//黑红数结构
else if (p instanceof TreeNode)
e = ((TreeNode)p).putTreeVal(this, tab, hash, key, value);
//链表结构
else {
for (int binCount = 0; ; ++binCount) {
if ((e = p.next) == null) {
p.next = newNode(hash, key, value, null);
//当链表的节点数超过8时,将链表转为红黑树
if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st
treeifyBin(tab, hash);
break;
}
if (e.hash == hash &&
((k = e.key) == key || (key != null && key.equals(k))))
break;
p = e;
}
}
if (e != null) { // existing mapping for key
V oldValue = e.value;
if (!onlyIfAbsent || oldValue == null)
e.value = value;
afterNodeAccess(e);
return oldValue;
}
}
++modCount;
if (++size > threshold)
//数组扩容
resize();
afterNodeInsertion(evict);
return null;
}
注意:
(1)数组原本的位置为空时
(2)数组原本的位置为不为空时,且下面是链表的结构
(3)数组原本的位置为不为空时,且下面是红黑树的结构
(4)若是key,hash值均相同时,进行内容的覆盖
图表:
二、
Map集合的特点:
1.Map集合是一个双列集合,一个元素包含两个值(一个Key,一个Value)
2.Map集合元素中,Key和value的数据类型可以相同,也可以不同
3.Map集合元素中,Key不允许重复,Value可以重复
4.Map集合元素中,Key与Value是一一对应的
Map集合的方法:
public V put(K key, V value) : 把指定的键与指定的值添加到Map集合中。
public V remove(Object key) : 把指定的键 所对应的键值对元素 在Map集合中删除,返回被删除元素的值。
boolean containsKey(Object key) 判断集合中是否包含指定的键。
public V get(Object key) 根据指定的键,在Map集合中获取对应的值。
public Set keySet() : 获取Map集合中所有的键,存储到Set集合中。
public Set> entrySet() : 获取到Map集合中所有的键值对对象的集合(Set集合)。
java.utils.HashMap集合 implements Map接口
HashMap的特点:
1.HashMap集合底层是哈希表,查询速度相当快
JDK1.8前:数组 + 链表
JDK1.8后:数组 + 链表/红黑树(链表的长度超过8),提高查询效率
2.HashMap集合是一个无序的集合,存储元素和取出元素的顺序有可能不一致
java.utils.LinkeHashMap集合 extends HashMap集合
LinkeHashMap的特点:
1.LinkeHashMap集合底层是哈希表 + 链表(保证迭代的顺序)
2.LinkeHashMap集合是一个有序的集合,存储元素和取出元素的顺序一致
三、
Map集合例子:
public class MapTest {
public static void main(String[] args) {
HashMap hashMap = new HashMap<>();
hashMap.put("秦问天","莫倾城");
hashMap.put("莫凡","书音");
hashMap.put("张小凡","碧瑶");
hashMap.put("唐三","小舞");
System.out.println(hashMap.containsKey("莫凡"));
System.out.println(hashMap.get("张小凡"));
System.out.println("..............");
System.out.println(hashMap.remove("唐三"));
System.out.println("..............");
for (String key : hashMap.keySet()) {
System.out.println(key);
System.out.println(hashMap.get(key));
System.out.println("..............");
}
System.out.println("..............");
for (Map.Entry entry : hashMap.entrySet()) {
System.out.println("key:"+entry.getKey()+"......"+"value:"+entry.getValue());
}
}
}