Java Hashmap内部
我对JavaJava Hashmap内部,java,arrays,hashmap,Java,Arrays,Hashmap,我对JavaHashMap类没有什么疑问。我的理解是 transient Entry[] table; 表数组将根据hashCode()的值保存数据。我需要知道这个数组何时初始化。数组长度是基于我们在HashMap初始化期间定义的容量,还是基于调用构造函数时未定义的默认容量16 哈希代码如何缩放到数组索引?例如,如果hashcode有一个巨大的值,那么如何将其缩放到数组索引(如10、20) 我已经读到,当达到阈值时,将发生重新灰化。例如,在默认情况下,当16是容量,0.75是负载系数时,阈值
HashMap
类没有什么疑问。我的理解是
transient Entry[] table;
表数组将根据hashCode()
的值保存数据。我需要知道这个数组何时初始化。数组长度是基于我们在HashMap
初始化期间定义的容量,还是基于调用构造函数时未定义的默认容量16
哈希代码如何缩放到数组索引?例如,如果hashcode有一个巨大的值,那么如何将其缩放到数组索引(如10、20)
我已经读到,当达到阈值时,将发生重新灰化。例如,在默认情况下,当16是容量,0.75是负载系数时,阈值为
16*0.75=12
。一旦添加12项,将进行再灰化,容量将增加。这是否意味着表
数组大小增加了?因为你的帖子有很多问题,我将列举你的问题作为我答案的一部分。另外,请注意,我要去寻找我的答案
public HashMap(int initialCapacity, float loadFactor) {
if (initialCapacity < 0)
throw new IllegalArgumentException("Illegal initial capacity: " +
initialCapacity);
if (initialCapacity > MAXIMUM_CAPACITY)
initialCapacity = MAXIMUM_CAPACITY;
if (loadFactor <= 0 || Float.isNaN(loadFactor))
throw new IllegalArgumentException("Illegal load factor: " +
loadFactor);
// Find a power of 2 >= initialCapacity
int capacity = 1;
while (capacity < initialCapacity)
capacity <<= 1;
this.loadFactor = loadFactor;
threshold = (int)(capacity * loadFactor);
table = new Entry[capacity];
init();
}
答:
表
数组仅在数据首次输入映射时初始化(例如put()
方法调用)。它不会作为映射本身实例化的一部分发生,除非调用复制构造函数,或者映射被反序列化为对象HashMap
初始化期间定义的容量,还是基于调用构造函数时未定义的默认容量16?答:正确,
表
数组的长度基于传递给构造函数的初始容量。当未指定初始容量且调用默认构造函数时,将使用默认容量答:有关实际执行此操作的代码,请参阅。基本上,代码采用非常大的散列值,并对表的最后一个元素索引执行
按位and
。这将有效地随机化键/值对与表
数组的位置。例如,如果散列值是333(在基数2中是101001101),并且表
数组大小是32(100000),那么最后一个元素索引将是31(11111)。因此,选择的索引将是11111&101001101==01101==13
A:差不多,是的。当超过
阈值时,将调整表的大小。请注意,通过调整大小,不会修改现有的表数组。而是创建一个新的表
数组,其容量是第一个表
数组的两倍。有关详细信息,请参阅
谢谢你,乔纳森。我几乎明白了。只是另一个问题,即与Q:3有关的问题。在这个示例中,您已经清楚地解释了如何将hashcode 333放入32长度的数组中。所以它意味着任何hashcode值都可以放入32长度的数组中。那么,调整大小的必要性是什么呢。在索引冲突的情况下,碰撞对象将存储在同一索引元素中。我说得对吗?在什么基础上调整大小?好问题。是的,可以在同一索引中存储多个元素,因为
表
数组的类型是HashMap
-节点
的内部类型,该节点引用了可能的下一个
节点。因此,以这种方式,固定大小的表
可以具有无限数量的条目。当键值对的数量(即HashMap
中的大小
字段)超过阈值
值(即表
数组的大小乘以加载因子
)时,通常会触发调整大小。因此,在调整大小时,会重新排列对象吗?在上面的示例中,当表大小为32时,占用哈希代码333的对象将位于第13位。在调整大小时,大小会增加一倍,所以现在的大小将变为64。为了避免混淆,我们再次考虑它会加倍到128,因为大小64也占据13的位置。与128,1111111和101001101==1001101==77。它会被存储在77位吗?关于调整大小,对象可能会被重新排列,是的。考虑大小为4的<代码>表<代码>(最后索引为3,在基2中为11),索引14(1110)的散列。在这种情况下,该值将存储在索引3&14==11&1110==0011&1110==10==2
处。随后,将表的大小调整为8(最后一个索引是7,或基数2中的111)。因此,当调整大小时,14将被索引为7&14==111&1110==0111&1110==110==6
。因此,相同元素的表
数组中的索引在调整大小时从2变为6。至于您对get()
方法的关注,节点不会“在彼此内部”索引。相反,您可以认为表
在每个索引处都有一个节点的链接列表,即使类型是Node[]
。这是因为节点
实例包含对下一个
节点的引用。有关详细信息,请参见节点
类的实现()。请注意,这称为链接。有关哈希表链接的描述,请参阅Wikipedia关于该主题的文章()。
void resize(int newCapacity) {
Entry[] oldTable = table;
int oldCapacity = oldTable.length;
if (oldCapacity == MAXIMUM_CAPACITY) {
threshold = Integer.MAX_VALUE;
return;
}
Entry[] newTable = new Entry[newCapacity];
transfer(newTable);
table = newTable;
threshold = (int)(newCapacity * loadFactor);
}