本文基于Java 1.7 进行分析,这次分析主要是作为自己的笔记留存。
HashMap基于哈希算法,使用put存放对象,get获取对象,在初始设置hashmap容量时,尽量设置为2的幂次方
get,用户传入K,然后根据hash值,计算位置,确定在桶中的位置,然后获取value,中间需要通过K的equals()方法,hash值,key是否相等,来确定是否是取到的值。put,用户将K-V传递给put后,通过K对象的hashcode()方法来计算本次存储的hash值,然后通过indexFor()方法,获取需要存入hash桶的位置,hash桶是一个数组,默认初始大小是16,里面存放的是Entry通过上文源码以及注释可以看到,在使用hashmap时,需要作为key的对象,必须实现了hashcode和equals两个方法,保证key的唯一性,因为在hashmap中,使用hashcode来确定位置,使用equals来确定是否重复,以及区分hash冲突的情况,因为hash冲突时,一般是hashcode值一样导致,但是两个对象通过equals方法,是可以确实是不等的,这也是为什么String为什么适合作为key的原因。
在put中有一个addEntry方法,这个方法用来将k-v存入hash桶,包括了hash冲突时的处理。
void addEntry(int hash, K key, V value, int bucketIndex) { //如果桶超过限制,一般为容量*0.75,就resize桶大小,扩展为2 * 当前大小 if ((size >= threshold) && (null != table[bucketIndex])) { resize(2 * table.length); hash = (null != key) ? hash(key) : 0; bucketIndex = indexFor(hash, table.length); } //创建Entry对象,并写入桶中 createEntry(hash, key, value, bucketIndex); } void createEntry(int hash, K key, V value, int bucketIndex) { Entry<K,V> e = table[bucketIndex]; table[bucketIndex] = new Entry<>(hash, key, value, e); size++; } Entry(int h, K k, V v, Entry<K,V> n) { value = v; next = n; key = k; hash = h; }通过上文代码可以看到,Entry是实际存储K-V的对象,同时也是用来解决hash冲突的单链表,当我们遇到hash冲突时,例如A,B,A已经存在桶中13这个位置,A,B hash冲突,这是,就是将B写入到A目前的位置,同时将A放入Entry的next的位置,链接起来。