Map接口及其HashMap的底层机制

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的底层一致。