热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

java中HashMap重要性质和优化总结

前言由于HashMap在java开发中占有的举足轻重的地位,所以对hashmap的一些重要性质和优化点进行一些总结就显得尤为重要了,同时也能在实际工作中提高hashMap的效率,但对于全面介绍

前言

  由于HashMap在java开发中占有的举足轻重的地位,所以对hashmap的一些重要性质和优化点进行一些总结就显得尤为重要了,同时也能在实际工作中提高hashMap的效率,但对于全面介绍分析hashMap,本文不做过多概述。本文主要是希望对java初学者或者是有意对hashMap的使用效率有更深了解的的读者提供帮助。

 

一、hashMap重要属性

  1、

  /**
   * The default initial capacity - MUST be a power of two.(map的初始大小)
   */
  DEFAULT_INITIAL_CAPACITY = 16;(默认大小)

 

  2、 

  /**
   * The maximum capacity, used if a higher value is implicitly specified
   * by either of the constructors with arguments.
   * MUST be a power of two <= 1<<30.

   *(最大容量,如果指定的容易大于最大容量,将使用此值)
   */
   MAXIMUM_CAPACITY = 1 <<30;(最大容量)

 

  3、 

  /**
   * The load factor used when none specified in constructor.
   */
   DEFAULT_LOAD_FACTOR = 0.75f;(默认负载因子)

 

  4、 

  /**
  * The next size value at which to resize (capacity * load factor).
  * (map是否扩容的决定性因素)
  */
  threshold;

 

  5、

  bucket(数组中最小存储单元,在源码中为Entry)

 

二、HashMap创建到put流程基本介绍

  hashMap由其名字可以知道,它使用的是哈希算法来管理存储其中的对象的,具体是用数组和链表两种数据结构管理的。

  1、初始化

    如果参数均为指定,则使用默认值初始化  

    this.loadFactor = DEFAULT_LOAD_FACTOR;
    threshold = (int)(DEFAULT_INITIAL_CAPACITY * DEFAULT_LOAD_FACTOR);
    table = new Entry[DEFAULT_INITIAL_CAPACITY];(这里就是初始化了一个数组,用于存放对象,buckets)

    如果指定loadFactor和initialCapacity,则

    this.loadFactor = loadFactor

    程序将利用initialCapacity计算一个新的capacity,capacity大小为大于初始容易值的最小的2的整数次幂的值(如初始容量为15,则capacity为16.初始为3,则capacity为4),

    threshold = (int)(capacity * loadFactor);

        table = new Entry[capacity];

  2、put

    put过程中,如果一个对象hash到同一个bucket,则会形成一个链表,链表查询是线性的。在对象放入map后,会检查map大小。如果map的size大于或等于threshold(capacity * load factor),注意不是在size大于capacity时扩容,则会以map两倍容量扩容(此步骤设计到重新申请空间和计算hash值,性能消耗比较大)

 

  三、优化hashMap

    如果哈希映射的内部数组只包含一个元素,则所有项将映射到此数组位置,从而构成一个较长的链接列表。由于我们的更新和访问使用了对链接列表的线性搜索,而这要比 Map 中的每个数组索引只包含一个对象的情形要慢得多,因此这样做的效率很低。访问或更新链接列表的时间与列表的大小线性相关,而使用哈希函数问或更新数组中的单个元素则与数组大小无关 — 就渐进性质(Big-O 表示法)而言,前者为 O(n),而后者为 O(1)。因此,使用一个较大的数组而不是让太多的项聚集在太少的数组位置中是有意义的。

    调整 Map 实现的大小

    在哈希术语中,内部数组中的每个位置称作“存储桶”(bucket),而可用的存储桶数(即内部数组的大小)称作容量 (capacity)。为使 Map 对象有效地处理任意数目的项,Map 实现可以调整自身的大小。但调整大小的开销很大。调整大小需要将所有元素重新插入到新数组中,这是因为不同的数组大小意味着对象现在映射到不同的索引值。先前冲突的键可能不再冲突,而先前不冲突的其他键现在可能冲突。这显然表明,如果将 Map 调整得足够大,则可以减少甚至不再需要重新调整大小,这很有可能显著提高速度。

    使用 1.4.2 JVM 运行一个简单的测试,即用大量的项(数目超过一百万)填充 HashMap。表 5 显示了结果,并将所有时间标准化为已预先设置大小的服务器模式(关联文件中的 。对于已预先设置大小的 JVM,客户端和服务器模式 JVM 运行时间几乎相同(在放弃 JIT 编译阶段后)。但使用 Map 的默认大小将引发多次调整大小操作,开销很大,在服务器模式下要多用 50% 的时间,而在客户端模式下几乎要多用两倍的时间!

表 5:填充已预先设置大小的 HashMap 与填充默认大小的 HashMap 所需时间的比较

  客户端模式 服务器模式
预先设置的大小 100% 100%
默认大小 294% 157%

 

    使用负载因子

为确定何时调整大小,而不是对每个存储桶中的链接列表的深度进行记数,基于哈希的 Map 使用一个额外参数并粗略计算存储桶的密度。Map 在调整大小之前,使用名为“负载因子”的参数指示 Map 将承担的“负载”量,即它的负载程度。负载因子、项数(Map 大小)与容量之间的关系简单明了:

 

  • 如果(负载因子)x(容量)>(Map 大小),则调整 Map 大小

 

    例如,如果默认负载因子为 0.75,默认容量为 11,则 11 x 0.75 = 8.25,该值向下取整为 8 个元素。因此,如果将第 8 个项添加到此 Map,则该 Map 将自身的大小调整为一个更大的值。相反,要计算避免调整大小所需的初始容量,用将要添加的项数除以负载因子,并向上取整,例如,

 

  • 对于负载因子为 0.75 的 100 个项,应将容量设置为 100/0.75 = 133.33,并将结果向上取整为 134(或取整为 135 以使用奇数)

 

  奇数个bucket使 map 能够通过减少冲突数来提高执行效率。虽然我所做的测试(关联文件中的 并未表明质数可以始终获得更好的效率,但理想情形是容量取质数。1.4 版后的某些 Map(如 HashMap 和 LinkedHashMap,而非 Hashtable 或 IdentityHashMap)使用需要 2 的幂容量的哈希函数,但下一个最高 2 的幂容量由这些 Map 计算,因此您不必亲自计算。

  负载因子本身是空间和时间之间的调整折衷。较小的负载因子将占用更多的空间,但将降低冲突的可能性,从而将加快访问和更新的速度。使用大于 0.75 的负载因子可能是不明智的,而使用大于 1.0 的负载因子肯定是不明知的,这是因为这必定会引发一次冲突。使用小于 0.50 的负载因子好处并不大,但只要您有效地调整 Map 的大小,应不会对小负载因子造成性能开销,而只会造成内存开销。但较小的负载因子将意味着如果您未预先调整 Map 的大小,则导致更频繁的调整大小,从而降低性能,因此在调整负载因子时一定要注意这个问题。

 

 


推荐阅读
  • 如何实现织梦DedeCms全站伪静态
    本文介绍了如何通过修改织梦DedeCms源代码来实现全站伪静态,以提高管理和SEO效果。全站伪静态可以避免重复URL的问题,同时通过使用mod_rewrite伪静态模块和.htaccess正则表达式,可以更好地适应搜索引擎的需求。文章还提到了一些相关的技术和工具,如Ubuntu、qt编程、tomcat端口、爬虫、php request根目录等。 ... [详细]
  • 深入解析Linux下的I/O多路转接epoll技术
    本文深入解析了Linux下的I/O多路转接epoll技术,介绍了select和poll函数的问题,以及epoll函数的设计和优点。同时讲解了epoll函数的使用方法,包括epoll_create和epoll_ctl两个系统调用。 ... [详细]
  • 手写HashMap,快手面试官直呼内行
    手写HashMap,快手面试官直呼内行-手写HashMap?这么狠,面试都卷到这种程度了?第一次见到这个面试题,是在某个不方便透露姓名的Offer收割机大佬的文章:这……我当 ... [详细]
  • 本文详细介绍了SQL日志收缩的方法,包括截断日志和删除不需要的旧日志记录。通过备份日志和使用DBCC SHRINKFILE命令可以实现日志的收缩。同时,还介绍了截断日志的原理和注意事项,包括不能截断事务日志的活动部分和MinLSN的确定方法。通过本文的方法,可以有效减小逻辑日志的大小,提高数据库的性能。 ... [详细]
  • Spring源码解密之默认标签的解析方式分析
    本文分析了Spring源码解密中默认标签的解析方式。通过对命名空间的判断,区分默认命名空间和自定义命名空间,并采用不同的解析方式。其中,bean标签的解析最为复杂和重要。 ... [详细]
  • 本文介绍了在Mac上搭建php环境后无法使用localhost连接mysql的问题,并通过将localhost替换为127.0.0.1或本机IP解决了该问题。文章解释了localhost和127.0.0.1的区别,指出了使用socket方式连接导致连接失败的原因。此外,还提供了相关链接供读者深入了解。 ... [详细]
  • Ubuntu安装常用软件详细步骤
    目录1.GoogleChrome浏览器2.搜狗拼音输入法3.Pycharm4.Clion5.其他软件1.GoogleChrome浏览器通过直接下载安装GoogleChro ... [详细]
  • HashMap的扩容知识详解
    本文详细介绍了HashMap的扩容知识,包括扩容的概述、扩容条件以及1.7版本中的扩容方法。通过学习本文,读者可以全面了解HashMap的扩容机制,提升对HashMap的理解和应用能力。 ... [详细]
  • 本文讨论了将HashRouter改为Router后,页面全部变为空白页且没有报错的问题。作者提到了在实际部署中需要在服务端进行配置以避免刷新404的问题,并分享了route/index.js中hash模式的配置。文章还提到了在vueJs项目中遇到过类似的问题。 ... [详细]
  • HashTable与ConcurrentHashMap均可实现HashMap的功能,对外提供了键值对存储的数据结构。但是在内部结构及实现上有何区别,性能上的差异到底在哪里又是如何导致的 ... [详细]
  • Java之HashMap在多线程情况下导致死循环的问题
    PS:不得不说Java编程思想这本书是真心强大..学习内容:1.HashMap<K,V>在多线程的情况下出现的死循环现象当初学Java的时候只是知道HashMap< ... [详细]
  • 转载自:http:www.blogjava.netCarpenterLeearchive20160427430268.html总体介绍之所以把HashSet和HashMa ... [详细]
  • 缓存这个东西就是为了提高运行速度的,由于缓存是在寸土寸金的内存里面,不是在硬盘里面,所以容量是很有限的。LRU这个算法就是把最近一次使用时间离现在时间最远的数据删除掉。先说说List:每 ... [详细]
  • 在Java中有多种遍历HashMap的方法,注意Java中所有的Map类型都实现了共有的Map接口,所以接下来方法适用于所有Map(如:HaspMap,TreeMap,Linked ... [详细]
  • Java面试 HashMap、HashSet源码解析
    本章所有源代码基于JDK1.8版本HashMap和HashSet是JavaCollectionFramework的两个重要成员,其中HashMap是Map接口的常用实现类,Hash ... [详细]
author-avatar
shamrock-wrh_186
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有