您的位置:首页 > 其它

第五章 HashMap源码解析

2016-01-06 16:47 423 查看
5.1、对于HashMap需要掌握以下几点

Map的创建:HashMap()

往Map中添加键值对:即put(Object key, Object value)方法

获取Map中的单个对象:即get(Object key)方法

删除Map中的对象:即remove(Object key)方法

判断对象是否存在于Map中:containsKey(Object key)

遍历Map中的对象:即keySet(),在实际中更常用的是增强型的for循环去做遍历

Map中对象的排序:主要取决于所采取的排序算法

5.2、构建HashMap

源代码:

一些属性:

static final int DEFAULT_INITIAL_CAPACITY = 16;    // 默认的初始化容量(必须是2的多少次方)
static final int MAXIMUM_CAPACITY = 1 << 30;    // 最大指定容量为2的30次方
static final float DEFAULT_LOAD_FACTOR = 0.75f;    // 默认的加载因子(用于resize)

transient Entry[] table;// Entry数组(数组容量必须是2的多少次方,若有必要会扩容resize)--这就是HashMap的底层数据结构

transient int size;        // 该map中存放的key-value对个数,该个数决定了数组的扩容(而非table中的所占用的桶的个数来决定是否扩容)
// 扩容resize的条件:eg.capacity=16,load_factor=0.75,threshold=capacity*load_factor=12,即当该map中存放的key-value对个数size>=12时,就resize)
int threshold;
final float loadFactor;    // 负载因子(用于resize)

transient volatile int modCount;// 标志位,用于标识并发问题


注意:

map中存放的key-value对个数size,该个数决定了数组的扩容(size>=threshold时,扩容),而非table中的所占用的桶的个数来决定是否扩容

标志位modCount采用volatile实现该变量的线程可见性(之后会在"Java并发"章节中去讲)

数组中的桶,指的就是table[i]

无参构造器(也是当下最常用的构造器)

/**
* 初始化一个负载因子、resize条件和Entry数组
*/
public HashMap() {
this.loadFactor = DEFAULT_LOAD_FACTOR;// 负载因子:0.75
threshold = (int) (DEFAULT_INITIAL_CAPACITY * DEFAULT_LOAD_FACTOR);//当该map中存放的key-value对个数size>=12时,就resize
table = new Entry[DEFAULT_INITIAL_CAPACITY];// 设置Entry数组容量为16
init();
}


注意:

init()为空方法

对于hashmap而言,还有两个比较常用的构造器,一个双参,一个单参。

final Entry<K, V> nextEntry() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
Entry<K, V> e = next;
if (e == null)
throw new NoSuchElementException();

if ((next = e.next) == null) {
Entry[] t = table;
while (index < t.length && (next = t[index++]) == null)
;
}
current = e;
return e;
}


View Code

总结:

HashMap底层就是一个Entry数组,Entry又包含next,事实上,可以看成是一个"链表数组"

扩容:map中存放的key-value对个数size,该个数决定了数组的扩容(size>=threshold时,扩容),而非table中的所占用的桶的个数来决定是否扩容

扩容过程,不会重新计算hash值,只会重新按位与

在实际使用中,若我们能预判所要存储的元素的多少,最好使用上述的单参构造器来指定初始容量

HashMap可以插入null的key和value

remove(Object key):若删除的key不存在于map中,返回null,不会抛异常。

HashMap线程不安全,若想要线程安全,最好使用ConcurrentHashMap

疑问:

在我们实际使用hashmap时,最好的情况是将key的hash值打散,使插入的这些Entry尽量落在不同的桶上[b](这样做的主要目的是提高查询效率),以下这个hash函数应该就是实现了这样的功能,但是为什么这样的hash函数可以将hash值打散,求大神指点!!![/b]

static int hash(int h) {
//这样的hash函数应该可以尽量将hash值打散
h ^= (h >>> 20) ^ (h >>> 12);
return h ^ (h >>> 7) ^ (h >>> 4);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: