Map接口及其HashMap的底层机制
map和set都是k-v不过set 的value是默认的PRESENT常量对象
Map接口的特点
1、用于保存具有映射关系的数据key-value
2、Map中的key-value可以是任何类型的数据,会封装到HashMap$Node对象中
就是HashSet中的Node对象
Node(int hash, K key, V value, Node<K,V> next) {
this.hash = hash;
this.key = key;
this.value = value;
this.next = next;
}
3、Map中的key不允许重复
再当key相同时,会用新的value值覆盖到原来的value值
4、Map中的value可以相同
5、Map中的key可以为空,但只能有一个。value可以为空可以有多个
6、key-value存在单项一对一的关系通过key找value
7、为了方便遍历,还会创建EntrySet集合,该集合存放的元素的类型为Entry,而一个Entry对象就有k,v EntrySet<Entry<k,v>>
transient Set<Map.Entry<K,V>> entrySet;
8、entrySet中定义的类型为Map.Entry,但是实际存放的还是 HashMap$Node
这是因为
class Node<K,V> implements Map.Entry<K,V>
9、当把HashMap$Node放到entrySet就方便遍历。因为Map.Entry提供了K getKey(),V getValue方法
entrySet中的Map.Entry<K,V>节点是指向Node<K,V>节点的
10、可以直接得到map的key集合和value集合
Set set1=map.keySet();
Collention values=map.values()
11、线程不安全,方法上没有加锁。
Map的常用方法
方法名称 | 说明 |
---|---|
V put(K key,V value) | 添加元素 |
V remove(Object key) | 根据键删除键值对元素 |
void clear() | 移除所有的键值对元素 |
boolean containsKey(Object key) | 判断集合是否包含指定的键 |
boolean containsValue(Object value) | 判断集合是否包含指定的值 |
boolean isEmpty() | 判断集合是否为空 |
int size() | 集合的长度,也就是集合中键值对的个数 |
HashMap的键相同时值的替换过程
final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
boolean evict) {
Node<K,V>[] tab; Node<K,V> p; int n, i;
if ((tab = table) == null || (n = tab.length) == 0)
n = (tab = resize()).length;
if ((p = tab[i = (n - 1) & hash]) == null)
tab[i] = newNode(hash, key, value, null);
else {
Node<K,V> e; K k;
if (p.hash == hash &&
((k = p.key) == key || (key != null && key.equals(k))))
e = p;//相同的key进入改语句将p赋值给e指向第一个含有改key的节点
else if (p instanceof TreeNode)
e = ((TreeNode<K,V>)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);
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) {
V oldValue = e.value;
if (!onlyIfAbsent || oldValue == null)//onlyIfAbsent可以自己设置是否替换默认为false
e.value = value;//将原来的value覆盖
afterNodeAccess(e);
return oldValue;
}
}
++modCount;
if (++size > threshold)
resize();
afterNodeInsertion(evict);
return null;
}
HashMap源码
执行构造方法
HashMap<Integer,Integer> map=new HashMap<>();
public HashMap() {
this.loadFactor = DEFAULT_LOAD_FACTOR; // 初始化加载因子0.75
}
执行put方法
map.put(1,2);
//执行hash(key)方法,计算hash值
public V put(K key, V value) {
return putVal(hash(key), key, value, false, true);
}
其他的步骤和HashSet的底层一致。