Java HashMap

HashMap (java.util.HashMap)Map接口最基本的一个哈希表实现,它不是线程安全的,同时允许keynullHashMap中的元素是无序的,也不保证顺序。HashMap的基本操作如getput性能稳定,也就是在时间复杂度上是稳定的。同时,有两个影响HashMap性能的参数:初始容量和加载因子。

默认加载因子

static final float DEFAULT_LOAD_FACTOR = 0.75f;

 

默认容量

static final int DEFAULT_INITIAL_CAPACITY = 16;

 

最大容量

HashMap最大容量为1 << 30,也就是230次方。

static final int MAXIMUM_CAPACITY = 1 << 30;

 

The maximum capacity, used if a higher value is implicitly specified

by either of the constructors with arguments.

MUST be a power of two <= 1<<30.

这个是HashMap中桶的最大容量,但并不是最大可put的元素的最大数量。最大可put的元素的数量为int的最大值,即231次方-1

 

 

HashMap构造

public HashMap()

 

Constructs an empty <tt>HashMap</tt> with the default initial capacity (16) and the default load factor (0.75).

 

public HashMap(int initialCapacity)

 

Constructs an empty <tt>HashMap</tt> with the specified initial capacity and the default load factor (0.75).

 

public HashMap(int initialCapacity, float loadFactor)

 

Constructs an empty <tt>HashMap</tt> with the specified initial capacity and load factor.

 

public HashMap(Map<? extends K, ? extends V> m)

 

Constructs a new <tt>HashMap</tt> with the same mappings as the specified <tt>Map</tt>.  The <tt>HashMap</tt> is created with default load factor (0.75) and an initial capacity sufficient to hold the mappings in the specified <tt>Map</tt>.

 

Threshold设置

 

threshold = (int)(capacity * loadFactor);

 

计算落桶的位置

 

int i = indexFor(hash, table.length);

 

static int indexFor(int h, int length) {

return h & (length-1);

}

 

 

关键字比较

 

e.hash == hash && ((k = e.key) == key || key.equals(k))

 

扩容

Map中的元素数目达到或超过threshold值时,将自动扩容,扩容后的容量是之前的两倍。

resize(2 * table.length)

 

 

重新计算哈希

在进行扩容时,需要重新计算哈希。

 

关键代码

 

允许keynull

private V putForNullKey(V value) {

for (Entry<K,V> e = table[0]; e != null; e = e.next) {

if (e.key == null) {

V oldValue = e.value;

            e.value = value;

            e.recordAccess(this);

            return oldValue;

        }

    }

    modCount++;

    addEntry(0, null, value, 0);

    return null;

}

容量设置

默认情况下,如果没有指定初始容量,默认初始化容量为16。如果指定了初始容量,如采用public HashMap(int initialCapacity, float loadFactor)这种构造方式,这里第一个参数指定初始容量,但并不是简单的将HashMap容量设置为该参数值,而是像这样的:

// Find a power of 2 >= initialCapacity

int capacity = 1;

while (capacity < initialCapacity)

capacity <<= 1;

它实际上指定的是一个2N次方的一个值,且这个值刚刚大于(不小于)指定的初始容量。从这里可以看出,HashMap的容量一定是一个2N次方的一个值,且最大为1 << 30

这段代码是什么意思?

if (oldCapacity == MAXIMUM_CAPACITY) {

threshold = Integer.MAX_VALUE;

return;

}

在进行扩容时,如果当前容量已经达到最大容量,这将threshold值设置为int的最大值,即231次方-1,并不再进行扩容,也就不需要再重新计算哈希从这里可以看出:HashMap最大容量为1 << 30,也就是230次方;最大可put的元素的数量为int的最大值,即231次方-1

 

 

 

HashMap实现的好吗?

HashMap实现的很好,但还不是很好。除了初始容量和加载因子这两个影响HashMap性能的参数,它还依赖于keyhashCode算法。同时,在计算哈希时计算了两次哈希。

static int hash(int h) {

// This function ensures that hashCodes that differ only by

// constant multiples at each bit position have a bounded

// number of collisions (approximately 8 at default load factor).

h ^= (h >>> 20) ^ (h >>> 12);

return h ^ (h >>> 7) ^ (h >>> 4);

}

这是第2次哈希计算,没具体研究。

 

猜你喜欢

转载自lobin.iteye.com/blog/2326558