Java Hashmap内部

时间:2016-01-15 05:10:08

标签: java arrays hashmap

我对Java HashMap类几乎没有疑问。我的理解是

 transient Entry[] table;

表数组将根据hashCode()的值保存数据。我需要知道这个数组何时初始化。数组长度是基于我们在HashMap初始化期间定义的容量,还是默认容量16,如果在调用构造函数时未定义它?

哈希码如何缩放到数组索引?例如,如果哈希码具有巨大的值,它如何缩放到数组索引,如10,20

我已经读过,当达到阈值时,将发生重新散列。例如,在默认情况下,当16是容量而0.75是负载因子时,则阈值为16*0.75=12。一旦添加了12个项目,将发生重新加载并且容量将增加。这是否意味着table数组大小会增加?

2 个答案:

答案 0 :(得分:6)

因为你的帖子有很多问题我会在你的答案中列举你的问题。此外,请注意我已离开HashMap's source code for Java 1.8 b132寻求答案。

  1. 问:我需要知道这个数组何时被初始化 答:table数组仅在数据首次输入地图时才会初始化(例如put()方法调用)。它不会作为地图实例化的一部分发生,除非调用复制构造函数,或者将地图反序列化为对象。
  2. 问:阵列长度是基于我们在HashMap初始化期间定义的容量,还是默认容量16,如果在调用构造函数时未定义它?
    答:正确,table数组的长度基于传递给构造函数的初始容量。如果未指定初始容量且调用默认构造函数,则使用默认容量。
  3. 问:哈希码如何缩放到数组索引?
    答:对于执行此操作的实际代码,请参阅implementation of the putVal() method。基本上发生的是代码获取非常大的哈希值并使用表的最后一个元素索引执行bitwise-AND。这有效地将键/值对的位置与table数组随机化。例如,如果散列值为333(基数为2的101001101)且table数组大小为32(100000),则最后一个元素索引为31(11111)。因此,选择的索引将是11111 & 101001101 == 01101 == 13
  4. 问:我已经读过,当达到阈值时,将发生重新散列。 ...这是否意味着表格数量增加了?
    答:或多或少,是的。超出threshold时,将调整表的大小。请注意,通过调整大小,现有的table数组不会被修改。相反,创建一个新的table数组,其容量是第一个table数组的两倍。有关详细信息,请参阅implementation of the resize() method

答案 1 :(得分:0)

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();
 }

以上代码块介绍了如何以及何时填充table

一旦发生重新散列,它就不会增加表数组的大小,因为你可以永远声明一次数组大小;它每次都会使用更新的大小创建一个新数组:

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);
 }