首页 > 编程语言 >HashMap优点总结及源码分析

HashMap优点总结及源码分析

时间:2024-10-18 23:19:38浏览次数:8  
标签:hash HashMap int value 源码 key return null 优点

HashMap优点总结:

  1. 可存储不同类型的数据:使用泛型来定义键和值的类型,兼容所有数据类型
  2. 高效的查找和插入操作:通过key的hash映射,实现快速的查找和插入操作。时间复杂度基本为O(1)
  3. 灵活的容量调整:可根据数据量增长自行动态扩容。当容量过大时,HashMap会自动进行缩容,从而提高空间利用率
  4. 节点转换:当链表中的节点个数超过8个时,结构会转换为红黑树,以减少平均查找时间,提高插入和删除操作的性能。
  5. 可存储大量数据:HashMap的存储空间只受限于计算机的内存大小。
  6. 支持快速迭代:HashMap提供了快速的迭代方法,可以方便地遍历所有的键值对。
  7. 优秀的算法1:表容量保证是2的幂数,容量-1做与运算的散列效果更好,同时便于计算扩容后元素位置,可以提高扩容效率
  8. 优秀的算法2:高效的容量值优化算法,借用位运算高效运算。输入容量-1,之后将后面的每一个二进制位都转为1,最后值+1,保证最终结果一定是大于等于当前值的最小2的幂
  9. 优秀的算法3:key的hash运算,key的hashcode值向右位运算,纳入高位影响,更好的实现扩散效果,同时减少hash碰撞
  10. 迭代器快速失败:HashMap的迭代器使用快速失败机制,通过modCount属性监测并发修改,即在迭代时如果有其他线程并发地修改了HashMap的结构(例如添加或删除键值对),那么迭代器会立即抛出ConcurrentModificationException异常,避免出现数据不一致的情况。

好的设计思想:根据不同数据量,灵活切换多样合适的数据结构,如Redis的数据结构中也有体现

源码解析:

HashMap类

public class HashMap<K,V> extends AbstractMap<K,V>
    implements Map<K,V>, Cloneable, Serializable {

泛型容纳所有类型的key,value包括null

属性解析

/**
 * 版本序列号,可保证当类增减属性后,依旧可以反序列化成功
 * 位运算,提醒大家hash表大小一定是2的幂
 */
private static final long serialVersionUID = 362498820763181265L;
static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // aka 16

/**
 * 总数量,默认最大容量;最大容量一定是2的幂数
 * 好处1:2的幂值-1做与运算散列效果更好
 * 好处2:便于计算扩容后元素位置可以提高扩容效率
 */
static final int MAXIMUM_CAPACITY = 1 << 30;

/**
 * 构造方法不指定时的默认负载因子
 * 达到总容量的75% 即resize扩容
 */
static final float DEFAULT_LOAD_FACTOR = 0.75f;

/**
 * 链表长度至少达到8 结构才能转为红黑树
 */
static final int TREEIFY_THRESHOLD = 8;

/**
 * 树的节点数减到6 退化为链表
 */
static final int UNTREEIFY_THRESHOLD = 6;

/**
 * 数组的长度至少达到64,链表才能转为红黑树
 */
static final int MIN_TREEIFY_CAPACITY = 64;

Node解析

Node存储实际key,value数据的结构,TreeNode的父类

    static class Node<K,V> implements Map.Entry<K,V> {
        final int hash;
        final K key;
        V value;
        Node<K,V> next;

        Node(int hash, K key, V value, Node<K,V> next) {
            this.hash = hash;
            this.key = key;
            this.value = value;
            this.next = next;
        }

        public final K getKey()        { return key; }
        public final V getValue()      { return value; }
        public final String toString() { return key + "=" + value; }

        public final int hashCode() {
            return Objects.hashCode(key) ^ Objects.hashCode(value);
        }

        public final V setValue(V newValue) {
            V oldValue = value;
            value = newValue;
            return oldValue;
        }

        public final boolean equals(Object o) {
            if (o == this)
                return true;
            if (o instanceof Map.Entry) {
                Map.Entry<?,?> e = (Map.Entry<?,?>)o;
                if (Objects.equals(key, e.getKey()) &&
                    Objects.equals(value, e.getValue()))
                    return true;
            }
            return false;
        }
    }

key的hash计算方式解析

    static final int hash(Object key) {
        int h;
        // 向右位运算,纳入高位影响,更好的实现扩散效果,同时减少hash碰撞,^运算结果不同为1相同为0
        return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
    }

tableSizeFor表扩容容量值优化方法解析

为保证key更好的分散效果及更佳的扩容效率,保证最大容量始终是2的幂

	/**
	 * 将输入容量规范化为2的幂          			       
	 * 算法逻辑:位运算效率更高。输入容量-1,之后将后面的每一个二进制位都转为1,最后值+1,保证最终结果一定是大于等于当前值的最小2的幂	
	 */
    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;
    }

Fields 其他属性解析

 /* ---------------- Fields -------------- */

    /**
     * The table, initialized on first use, and resized as
     * necessary. When allocated, length is always a power of two.
     * (We also tolerate length zero in some operations to allow
     * bootstrapping mechanics that are currently not needed.)
     * transient 修饰,序列化会忽略此属性
     */
    transient Node<K,V>[] table;

    /**
     * Holds cached entrySet(). Note that AbstractMap fields are used
     * for keySet() and values().
     */
    transient Set<Map.Entry<K,V>> entrySet;

    /**
     * The number of key-value mappings contained in this map.
     */
    transient int size;

    /**
     * The number of times this HashMap has been structurally modified
     * Structural modifications are those that change the number of mappings in
     * the HashMap or otherwise modify its internal structure (e.g.,
     * rehash).  This field is used to make iterators on Collection-views of
     * the HashMap fail-fast.  (See ConcurrentModificationException).
     * 在HashMap中用于记录结构修改次数,以支持Fail-Fast机制并防止并发修改导致的不一致操作。
     */
    transient int modCount;

    /**
     * The next size value at which to resize (capacity * load factor).
     *
     * @serial
     */
    // (The javadoc description is true upon serialization.
    // Additionally, if the table array has not been allocated, this
    // field holds the initial array capacity, or zero signifying
    // DEFAULT_INITIAL_CAPACITY.)
    int threshold;

    /**
     * The load factor for the hash table.
     *
     * @serial
     */
    final float loadFactor;

put方法解析

第一次初始化hash表是在第一次调用put的时候

插入,更新,获取都是大体思路相同

  1. 判断表是否为null或长度length=0
  2. 定位到hash桶中key的位置
  3. 判断头结点是否存在并进行处理
  4. 判断为树结构并进行处理
  5. 判断为链表结构并进行处理

    /**
     * Associates the specified value with the specified key in this map.
     * If the map previously contained a mapping for the key, the old
     * value is replaced.
     *
     * @param key key with which the specified value is to be associated
     * @param value value to be associated with the specified key
     * @return the previous value associated with <tt>key</tt>, or
     *         <tt>null</tt> if there was no mapping for <tt>key</tt>.
     *         (A <tt>null</tt> return can also indicate that the map
     *         previously associated <tt>null</tt> with <tt>key</tt>.)
     */
    public V put(K key, V value) {
        return putVal(hash(key), key, value, false, true);
    }

    /**
     * Implements Map.put and related methods
     *
     * @param hash hash for key
     * @param key the key
     * @param value the value to put
     * @param onlyIfAbsent if true, don't change existing value
     * @param evict if false, the table is in creation mode.
     * @return previous value, or null if none
     */
    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;
        // hash桶定位计算方法(n - 1) & hash。模运算也可以做到,但是没有位运算效率高
        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;
            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) { // 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;
    }

标签:hash,HashMap,int,value,源码,key,return,null,优点
From: https://blog.csdn.net/qq_44845473/article/details/141233333

相关文章

  • 【Agent系列】从论文到源码解析Self-Ask 以及数据构建带来的启发
    前言一、Self-Ask解决了什么二、Self-Ask的理论实现三、从源码看Self-Ask的实现四、从实验结果看LLM的内部机制五、数据集的构建细节六、资料链接总结前言Self-Ask对LLM的推理能力进行了实验评估,并且提出了一种follow-up范式来提升LLM的2跳推理能力,为了进一步提升回答准确率......
  • 基于nodejs+vue基于SpringBoot框架的图书分享系统的设计与开发[开题+源码+程序+论文]
    本系统(程序+源码+数据库+调试部署+开发环境)带文档lw万字以上,文末可获取源码系统程序文件列表开题报告内容一、选题背景关于图书分享系统的研究,现有研究主要以传统的图书管理系统为主,侧重于图书的借阅、归还以及基本信息管理等功能,而专门针对基于SpringBoot框架的图书分享......
  • 基于nodejs+vue基于SpringBoot框架的球鞋洗护平台[开题+源码+程序+论文]计算机毕业设
    本系统(程序+源码+数据库+调试部署+开发环境)带文档lw万字以上,文末可获取源码系统程序文件列表开题报告内容一、选题背景在当今社会,球鞋文化盛行,越来越多的人热衷于收藏和穿着各种球鞋。然而,球鞋的洗护却成为了一个困扰众多球鞋爱好者的问题。关于球鞋洗护的研究,现有研究主......
  • 基于nodejs+vue基于springboot框架的企业合同管理系统设计与实现[开题+源码+程序+论文
    本系统(程序+源码+数据库+调试部署+开发环境)带文档lw万字以上,文末可获取源码系统程序文件列表开题报告内容一、选题背景关于企业合同管理系统的研究,现有研究主要以大型企业的综合管理系统为主,专门针对基于SpringBoot框架构建企业合同管理系统的研究较少。在国内外,企业合同......
  • 基于nodejs+vue基于SpringBoot框架的民俗文化交流与交易平台的设计与实现[开题+源码+
    本系统(程序+源码+数据库+调试部署+开发环境)带文档lw万字以上,文末可获取源码系统程序文件列表开题报告内容一、选题背景随着互联网的发展,文化交流与交易平台在各类文化领域逐渐兴起。关于民俗文化交流与交易平台的研究,现有研究主要以大型综合文化平台为主,专门针对民俗文化......
  • 基于nodejs+vue基于springboot和vue技术实现的电商系统[开题+源码+程序+论文]计算机毕
    本系统(程序+源码+数据库+调试部署+开发环境)带文档lw万字以上,文末可获取源码系统程序文件列表开题报告内容一、选题背景关于电商系统的研究,现有研究多集中在大型电商平台的商业模式、营销策略等宏观层面。在技术实现方面,虽然有多种技术组合被用于构建电商系统,但专门针对Spr......
  • 基于nodejs+vue基于springboot和vue技术的视频与图集网站[开题+源码+程序+论文]计算机
    本系统(程序+源码+数据库+调试部署+开发环境)带文档lw万字以上,文末可获取源码系统程序文件列表开题报告内容一、选题背景关于视频与图集网站的研究,现有研究主要集中在大型综合视频平台或者单一功能的视频网站方面,专门针对结合视频与图集功能的网站研究较少。在国内外,视频网......
  • 计算机毕业设计 | java swing 销售管理系统(附源码)
    1,概述1.1选题背景近几年来,传统商业与电商似乎是水火不容,大有不是你死便是我活的劲头。一直以来舆论都是一边倒的电商将迅速取代传统零售的论调,然而几年过去,电商的发展确实值得侧目,但传统商业虽然受到不小的影响,也依然顽强地挺立。事实上,就零售市场总规模而言,仍然是实体......
  • 计算机毕业设计 | vue+springboot 移动端在线考试系统(附源码)
    1,绪论研究背景与意义在20世纪末期,国家提出了教育要面向四个现代化,同时也提出了要大力发展教育手段和教育方式的信息化建设。在这样的背景和需求下,基于当今的互联网技术和计算机信息技术的课程在线考试系统就应运而生了。人们急切地需要再课程在线考试中利用现代网络技术达......
  • 基于nodejs+vue基于SpringBoot和Vue的农产品智能交易系统[开题+源码+程序+论文]计算机
    本系统(程序+源码+数据库+调试部署+开发环境)带文档lw万字以上,文末可获取源码系统程序文件列表开题报告内容一、选题背景随着信息技术的快速发展,农产品交易领域也在逐渐走向智能化。关于农产品交易系统的研究,现有研究主要以传统交易模式的改进为主,专门针对结合SpringBoot和......