Map

简介: Map

Map

  • Map关系图
对象名称 具体实现 线程是否安全 是否有序 是否允许空
Hashtable 基于数组、Entry实体 安全
HashMap Comparator、Entry实体 不安全
  • HashMap基本原理
  • 基本结构:水平轴为数组,垂直轴为链表
  • HashMap的初始容量为16,默认的负载因子为0.75;当数据量大于容量*负载因子时,此时则扩容;
  • HashMap如何扩容?通过位运算左移1位
  • HashMap如何解决Hash冲突?通过拉链法解决Hash冲突
  • HashMap何时进行链表结构变换?当链表长度数目大于8且Table长度大于64时
  • HashMap如何解决线程不安全?
  • 使用HashTable
  • 使用ConcurrentHashMap
  • 使用Collections.synchronizedMap
  • TreeMap基础
  • 不允许出现重复的Key
  • 不允许key、Value为空
  • 可排序
  • HashTable基础
  • 不允许key、Value为空
  • 线程安全
  • LinkedHashMap基础
  • 基于HashMap,维护了一个链表
  • HashMap源码分析
  • HashMap流程图:
  • HashMap关键方法
• tableSizeFor(initialCapacity):容量初始化;通过|,>>>运算保证容量始终为二的幂次;纠正用户输入的上限值为2的幂次
/**
 * Returns a power of two size for the given target capacity.
 */
static final int tableSizeFor(int cap) {
    int n = cap - 1;
    n |= n >>> 1;
    n |= n >>> 2;
    n |= n >>> 4;
    n |= n >>> 8;
    n |= n >>> 16;
    return (n < 0) ? 1 : (n >= MAXIMUM_CAPACITY) ? MAXIMUM_CAPACITY : n + 1;
}
• putVal()方法:插入数据
final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
               boolean evict) {
    Node<K,V>[] tab; Node<K,V> p; int n, i;
    //判断table是否为空
    if ((tab = table) == null || (n = tab.length) == 0)
        //初始化table大小
        n = (tab = resize()).length;
    //tab[i]是否存在元素
    if ((p = tab[i = (n - 1) & hash]) == null)
    //tab[i]如果不存在,则直接插入
        tab[i] = newNode(hash, key, value, null);
    else {
        Node<K,V> e; K k;
        //记录节点p
        if (p.hash == hash &&
            ((k = p.key) == key || (key != null && key.equals(k))))
            e = p;
        //如果p节点是树节点
        else if (p instanceof TreeNode)
        //则直接插入
            e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value);
        else {
        //遍历p链表
            for (int binCount = 0; ; ++binCount) {
                //如果p的下一个节点为null
                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;
            }
        }
        //如果节点存在,则解决Hash冲突
        if (e != null) { // existing mapping for key
            V oldValue = e.value;
            if (!onlyIfAbsent || oldValue == null)
                e.value = value;
            afterNodeAccess(e);
            return oldValue;
        }
    }
    //修改标志位modCount,fail-fast机制;保证并发的安全性
    ++modCount;
    if (++size > threshold)
        resize();
    afterNodeInsertion(evict);
    return null;
}

• resize()方法:初始化、扩容

final Node<K,V>[] resize() {
    Node<K,V>[] oldTab = table;
    //获取tab的大小
    int oldCap = (oldTab == null) ? 0 : oldTab.length;
    int oldThr = threshold;
    int newCap, newThr = 0;
    //如果tab.length大于0
    if (oldCap > 0) {
        //如果tab大于MAX_INTEGER,则直接返回
        if (oldCap >= MAXIMUM_CAPACITY) {
            threshold = Integer.MAX_VALUE;
            return oldTab;
        }
        //如果容量扩大两倍后,依然小于MAXIMUM_CAPACITY;且tab.length大于64
        else if ((newCap = oldCap << 1) < MAXIMUM_CAPACITY &&
                 oldCap >= DEFAULT_INITIAL_CAPACITY)
            //阈值也扩容为原来的两倍
            newThr = oldThr << 1; // double threshold
    }
    //当通过initialCapacity构造方法构造map时,初始化时定义了oldThr
    else if (oldThr > 0) // initial capacity was placed in threshold
        //将oldThr赋予newCap
        newCap = oldThr;
    //默认无参构造方法
    else {
        //初始化容量为16;阈值为12
        newCap = DEFAULT_INITIAL_CAPACITY;
        newThr = (int)(DEFAULT_LOAD_FACTOR * DEFAULT_INITIAL_CAPACITY);
    }
    //如果新的阈值为0
    if (newThr == 0) {
        float ft = (float)newCap * loadFactor;
        //修正新的阈值
        newThr = (newCap < MAXIMUM_CAPACITY && ft < (float)MAXIMUM_CAPACITY ?
                  (int)ft : Integer.MAX_VALUE);
    }
    threshold = newThr;
    //扩容之后的元素复制操作    
    @SuppressWarnings({"rawtypes","unchecked"})
        Node<K,V>[] newTab = (Node<K,V>[])new Node[newCap];
    table = newTab;
//接下来属于扩容完成后的元素复制操作.......
}
• hash(Object key):HashMap的hash策略,将高位地址转换为低位地址,防止高位、地位地址分布不均;解决易发生Hash冲突
static final int hash(Object key) {
    int h;
    //通过key的hashcode与key的hashcode无符号右移16位作异或运算
    return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}
  • HashMap允许key为null;
目录
相关文章
使用JavaStream将List转为Map
使用JavaStream将List转为Map
|
6月前
|
Java
map.getOrDefault
map.getOrDefault
55 0
|
6月前
|
存储 缓存 Java
map应用
map应用
77 0
|
6月前
|
存储 算法 安全
Map中的那些事
Map中的那些事
59 0
|
6月前
|
算法 C++ Python
map的使用(C++)
map的使用(C++)
66 0
|
11月前
|
存储 安全 Java
Map详解
Map详解
106 0
|
JSON 数据库 数据格式
Map和List的碰撞
Map和List的碰撞
55 0
|
机器学习/深度学习 计算机视觉
简单理解mAP究竟是什么
简单理解mAP究竟是什么
简单理解mAP究竟是什么
|
Java API Maven
List 转 Map, 齐活!(一)
大家好,我是指北君。 在我们平时的工作中,充满了各种类型之间的转换。今天指北君带大家上手 List 转 Map 的各种操作。 我们将假设 List 中的每个元素都有一个标识符,该标识符将在生成的 Map 中作为一个键使用。
List 转 Map, 齐活!(一)