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;
目录
相关文章
|
编解码 安全 索引
媒体编解码器MediaCodec
媒体编解码器MediaCodec
533 0
|
编解码 Ubuntu 虚拟化
【问题解决】VMware安装ubuntu操作系统出现分辨率的问题
【问题解决】VMware安装ubuntu操作系统出现分辨率的问题
2155 0
【问题解决】VMware安装ubuntu操作系统出现分辨率的问题
ElasticSearch Task命令说明
ElasticSearch task相关命令,以及返回信息解读。
5682 0
ElasticSearch Task命令说明
|
12月前
|
大数据 Linux 数据库
openEuler操作系统介绍
openEuler是一款开源免费的操作系统,由openEuler社区运作,支持多种处理器,适用于数据库、大数据、云计算等场景。它源自华为EulerOS,现分为创新版和LTS版,分别每半年和每两年发布一次。本课程以openEuler 20.03 LTS版为例,介绍其安装流程和环境准备。
1029 3
|
NoSQL 测试技术 MongoDB
使用同步和异步方式更新插入MongoDB数据的性能对比
在这篇文章中,我将探讨如何使用同步和异步方式插入数据到MongoDB,并对两种方式的性能进行对比。并将通过Python中的 pymongo 和 motor 库分别实现同步和异步的数据插入,并进行测试和分析。
|
存储 数据采集 JSON
彻底搞懂监控系统,使用Prometheus +Grafana搭建完整的应用监控系统
监控是运维系统的基础,我们衡量一个公司/部门的运维水平,看他们的监控系统就可以了。一个完善的监控系统可以提高应用的可用性和可靠性,在提供更优质服务的前提下,降低运维的投入和工作量,为用户带来更多的商业利益和客户体验。下面就带大家彻底搞懂监控系统,使用Prometheus +Grafana搭建完整的应用监控系统。
15856 1
彻底搞懂监控系统,使用Prometheus +Grafana搭建完整的应用监控系统
|
NoSQL C++ 容器
每天学点GDB(五)
本节分享使用GDB来进行STL容器的调试。
1923 0
|
测试技术