HashMap是java中用的非常多的一个容器,HashMap实现了Map接口的V get(K key),put(K key,V value)这两个方法。
HashMap的底层实现为一个数组,每个数组元素存储的是一个List<entrySet<K,V>>,该数组的默认长度DEFAULT_INITIAL_CAPACITY为16,默认装载因子DEFAULT_LOAD_FACTOR为0.75,如果该HashMap保存的键值对数量达到了16*0.75=12,该数组就会扩容到原来的两倍。
在hashMap的每次扩容的时候,将会重新计算每个key的桶位(即数组的某个下标),这个过程比较费时。如果能够事先估计出HashMap的容量,在初始化HashMap的时候设置合理的数组长度以及装载因子,避免扩容操作,可以提高put效率。
我们平时通过get(key)得到value感觉很快,这其实是因为hashMap用到了散列函数把key映射到了某一个桶位,这样在调用get(key)的时候就不是线性查找数组。查找到某桶位的时间复杂度为O(1),不会随着数组长度的变化而改变。
那么是不是说调用get(key)的时间复杂度就永远是O(1)呢?并不是这样的。因为不同的key通过散列函数可能映射到同一桶位,在每一个桶位里还是需要通过遍历list来查找唯一的一个key。所以,随着list.size()的不断增加,get(key)的时间复杂度会大于O(1),等于O(list.size())。所以如果能设计一个理想的散列函数,使得每一个不同的key都能映射到不同的桶位,那么get(key)的时间复杂度就是O(1)。但是要达到O(1)的性能,需要数组的长度比较长,并且装载因子比较低,这样散列冲突的可能性才比较小。