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

java学习hashmap(2)

HashMap的规约JavaDocs中HashMap的spec是这么写的:Hashtablebased implementationoftheMapinterface.Thisim

HashMap的规约

JavaDocs中HashMap的spec是这么写的:


Hash table based implementation of the Map interface. This implementation provides all of the optional map operations, and permits null values and the null key. (The HashMap class is roughly equivalent to Hashtable, except that it is unsynchronized and permits nulls.) This class makes no guarantees as to the order of the map; in particular, it does not guarantee that the order will remain constant over time.


这里头可提取出几个关键的信息:



  • 基于Map接口实现

  • 允许null键/值

  • 非同步

  • 不保证有序(如插入的顺序)

  • 不保证顺序不随时间变化。

这些问题在上篇都已经基本解释清楚了。下篇中,我们顺着HashMap的规约继续往下探索。


两个因子

有两个因子直接影响HashMap的效率,



  • 初始容量(initial capacity)。容量是指哈希表中桶的数量,而初始容量顾名思义就是HashMap实例创建时的最初容量。

  • 载入因子(Load factor)。含义在上篇已经阐述。

JavaDocs的原文对这两个因子是这样描述的:




  • Initial capacity. The capacity is the number of buckets in the hash table, The initial capacity is simply the capacity at the time the hash table is created.

  • Load factor. The load factor is a measure of how full the hash table is allowed to get before its capacity is automatically increased.


简单的说,容量(Capacity)就是桶(buckets)的数目,载入因子就是有数据的桶占所有桶的最大比例。如果对迭代性能要求很高的话不要把容量设置过大,也不要把载入因子设置过小。当有数据的桶的数目(即HashMap中元素的个数)大于Capacity * LoadFactor时就需要调整桶的数目为当前的两倍,也就是上篇所说的扩张。


初始容量

HashMap的默认初始容量为16。把它设成2的幂次是有意为之。我们再回顾一下index的计算:

index = hash(Key) & (length - 1)

因为length是,所以length - 1是,也就是个1,index就相当于是hash(Key)的最后位。这样,只要保证hash(Key)是均匀的,index的分布也就一定是均匀的。此外,这样设计算法使得可以用位运算计算index,避免了取模等效率低下的运算方式,提高了运算效率。

另外,需要注意的是,hash(Key)并不是hashCode(Key)hash方法的定义如下:

static final int hash(Object key) {
int h;
return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}

 

可以看到这个函数大概的作用就是:高16位不变,低16位和高16位做了一个异或。其中代码注释是这样写的:


Computes key.hashCode() and spreads (XORs) higher bits of hash to lower. Because the table uses power-of-two masking, sets of hashes that vary only in bits above the current mask will always collide. (Among known examples are sets of Float keys holding consecutive whole numbers in small tables.) So we apply a transform that spreads the impact of higher bits downward. There is a tradeoff between speed, utility, and quality of bit-spreading. Because many common sets of hashes are already reasonably distributed (so don’t benefit from spreading), and because we use trees to handle large sets of collisions in bins, we just XOR some shifted bits in the cheapest possible way to reduce systematic lossage, as well as to incorporate impact of the highest bits that would otherwise never be used in index calculations because of table bounds.


也就是说,设计者认为直接用hashCode(Key)的值很容易发生碰撞。为什么这么说呢?不妨思考一下,在为15(0x1111)时,其实散列真正生效的只是低4位,当然容易碰撞了。

因此,设计者采取了顾全大局的方法(综合考虑了速度、作用、质量),即把高16位和低16位异或了一下(也就是hash方法的作用)。设计者还解释到因为现在大多数的hashCode的分布已经很不错了,就算是发生了碰撞也用的红黑树去做了(下文会提到)。仅仅异或一下,既减少了系统的开销,也不会造成的因为高位没有参与下标的计算而引起的碰撞。

至于为什么偏偏设成2的4次幂,一般认为没什么特别的理由,用4次幂可能只是因为作者认为16这个初始容量是能符合常用的情景而已。



推荐阅读
  • 深入理解Redis的数据结构与对象系统
    本文详细探讨了Redis中的数据结构和对象系统的实现,包括字符串、列表、集合、哈希表和有序集合等五种核心对象类型,以及它们所使用的底层数据结构。通过分析源码和相关文献,帮助读者更好地理解Redis的设计原理。 ... [详细]
  • 深入解析Java枚举及其高级特性
    本文详细介绍了Java枚举的概念、语法、使用规则和应用场景,并探讨了其在实际编程中的高级应用。所有相关内容已收录于GitHub仓库[JavaLearningmanual](https://github.com/Ziphtracks/JavaLearningmanual),欢迎Star并持续关注。 ... [详细]
  • 深入解析Redis内存对象模型
    本文详细介绍了Redis内存对象模型的关键知识点,包括内存统计、内存分配、数据存储细节及优化策略。通过实际案例和专业分析,帮助读者全面理解Redis内存管理机制。 ... [详细]
  • JavaScript 基础语法指南
    本文详细介绍了 JavaScript 的基础语法,包括变量、数据类型、运算符、语句和函数等内容,旨在为初学者提供全面的入门指导。 ... [详细]
  • Redux入门指南
    本文介绍Redux的基本概念和工作原理,帮助初学者理解如何使用Redux管理应用程序的状态。Redux是一个用于JavaScript应用的状态管理库,特别适用于React项目。 ... [详细]
  • Startup 类配置服务和应用的请求管道。Startup类ASP.NETCore应用使用 Startup 类,按照约定命名为 Startup。 Startup 类:可选择性地包括 ... [详细]
  • 本文将深入探讨如何在不依赖第三方库的情况下,使用 React 处理表单输入和验证。我们将介绍一种高效且灵活的方法,涵盖表单提交、输入验证及错误处理等关键功能。 ... [详细]
  • 在Java中,this是一个引用当前对象的关键字。如何通过this获取并显示其所指向的对象的属性和方法?本文详细解释了this的用法及其背后的原理。 ... [详细]
  • 开发笔记:9.八大排序
    开发笔记:9.八大排序 ... [详细]
  • 本题探讨了在一个有向图中,如何根据特定规则将城市划分为若干个区域,使得每个区域内的城市之间能够相互到达,并且划分的区域数量最少。题目提供了时间限制和内存限制,要求在给定的城市和道路信息下,计算出最少需要划分的区域数量。 ... [详细]
  • 本文探讨了在C++中如何有效地清空输入缓冲区,确保程序只处理最近的输入并丢弃多余的输入。我们将介绍一种不阻塞的方法,并提供一个具体的实现方案。 ... [详细]
  • 本文详细介绍了 org.apache.commons.io.IOCase 类中的 checkCompareTo() 方法,通过多个代码示例展示其在不同场景下的使用方法。 ... [详细]
  • 问题描述:通过添加最少数量的括号,使得给定的括号序列变为合法,并输出最终的合法序列。数据范围:字符串长度不超过100。涉及算法:区间动态规划(Interval DP)。 ... [详细]
  • 本题来自WC2014,题目编号为BZOJ3435、洛谷P3920和UOJ55。该问题描述了一棵不断生长的带权树及其节点上小精灵之间的友谊关系,要求实时计算每次新增节点后树上所有可能的朋友对数。 ... [详细]
  • 本文介绍了如何使用JavaScript的Fetch API与Express服务器进行交互,涵盖了GET、POST、PUT和DELETE请求的实现,并展示了如何处理JSON响应。 ... [详细]
author-avatar
mobiledu2502903717
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有