8.7 HashSet和HashMap的性能选项
8.7 HashSet和HashMap的性能选项
对于HashSet
及其子类而言,它们采用hash
算法来决定集合中元素的存储位置,并通过hash
算法来控制集合的大小;
对于HashMap
、Hashtable
及其子类而言,它们采用hash
算法来决定Map
中key
的存储,并通过hash
算法来增加key
集合的大小。
hash存储示意图
hash
表里可以存储元素的位置被称为”桶(bucket
)”,在通常情况下,单个”桶”里存储一个元素,此时有最好的性能:hash
算法可以根据hashCode
值计算出”桶”的存储位置,接着从”桶”中取出元素。但hash
表的状态是open
的:在发生”hash
冲突”的情况下,单个桶会存储多个元素,这些元素以链表
形式存储,必须按顺序搜索。如图8.8所示是hash
表保存各元素,且发生”hash
冲突”的示意图。
hash表中的属性
因为HashSet
和HashMap
、Hashtable
都使用hash
算法来决定其元素(HashMap
则只考虑key)
的存储,因此HashSet
、HashMap
的hash
表包含如下属性:
hash表属性 | 描述 |
---|---|
容量(capacity ) |
hash 表中桶的数量。 |
初始化容量(initial capacity ) |
创建hash 表时桶的数量。HashMap 和HashSet 都允许在构造器中指定初始化容量 |
尺寸(size ) |
当前hash 表中记录的数量。 |
负载因子(load factor) |
负载因子等于”size除以capacity “。
hash 表具有冲突少 、适宜插入 与查询 的特点(但是使用Iterator 迭代元素时比较慢)。 |
负载极限
除此之外,hash
表里还有一个”负载极限”,”负载极限”是一个0到1的数值,”负载极限”决定了hash
表的最大填满程度。当hash
表中的负载因子达到指定的”负载极限”时,hash
表会自动成倍地增加容量(桶的数量),**并将原有的对象重新分配,放入新的桶内,这称为rehashing
**。HashSet
和HashMap
、Hashtable
的构造器允许指定一个负载极限,HashSet
和HashMap
、Hashtable
默认的”负载极限”为0.75
,这表明默认情况下,当该hash
表的4分之3
已经被填满时,hash
表会发生rehashing
。
负载极限如何取舍
“负载极限”的默认值(0.75)是时间和空间成本上的一种折中:
较高的”负载极限”可以降低hash
表所占用的内存空间,但会增加查询数据的时间开销,而查询是最频繁的操作
(HashMa
的get()
与put()
方法都要用到查询);
较低的”负载极限”会提高查询数据的性能,但会增加hash
表所占用的内存开销。
程序员可以根据实际情况来调整HashSet
和HashMap
的”负载极限”值
如果开始就知道HashSet
和HashMap
、Hashtable
会保存很多记录,则可以在创建时就使用较大的初始化容量
,如果初始化容量始终大于HashSet
和HashMap
、Hashtable
所包含的最大记录数除以”负载极限”,就不会发生rehashing
。使用足够大的初始化容量创建HashSet
和HashMap
、Hashtable
时,可以更高效地增加记录,但将初始化容量设置太高可能会浪费空间,因此通常不要将初始化容量设置得过高。