ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

java学习 hashmap(2)

2021-07-02 23:34:25  阅读:243  来源: 互联网

标签:index capacity hash hashmap 16 学习 table java HashMap


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这个初始容量是能符合常用的情景而已。

标签:index,capacity,hash,hashmap,16,学习,table,java,HashMap
来源: https://www.cnblogs.com/nbwzyzngyl/p/14965233.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有