源码解析 HashMap底层实现和原理( 三 )

e = table[bucketIndex];table[bucketIndex] = new Entry<>(hash, key, value, e);size++;}
添加到方法的具体操作,在添加之前先进行容量的判断,如果当前容量达到了阈值,并且需要存储到Entry[]数组中,先进性扩容操作,空充的容量为table长度的2倍 。重新计算hash值,和数组存储的位置,扩容后的链表顺序与扩容前的链表顺序相反 。然后将新添加的Entry实体存放到当前Entry[]位置链表的头部 。在1.8之前,新插入的元素都是放在了链表的头部位置,但是这种操作在高并发的环境下容易导致死锁,所以1.8之后,新插入的元素都放在了链表的尾部 。
4、获取方法:get
public V get(Object key) {if (key == null)//返回table[0] 的value值return getForNullKey();Entry entry = getEntry(key);return null == entry ? null : entry.getValue();}final Entry getEntry(Object key) {if (size == 0) {return null;}int hash = (key == null) ? 0 : hash(key);for (Entry e = table[indexFor(hash, table.length)];e != null;e = e.next) {Object k;if (e.hash == hash &&((k = e.key) == key || (key != null && key.equals(k))))return e;}return null;}
在get方法中,首先计算hash值,然后调用()方法得到该key在table中的存储位置,得到该位置的单链表,遍历列表找到key和指定key内容相等的Entry,返回entry.value值 。
5、删除方法
public V remove(Object key) {Entry e = removeEntryForKey(key);return (e == null ? null : e.value);}final Entry removeEntryForKey(Object key) {if (size == 0) {return null;}int hash = (key == null) ? 0 : hash(key);int i = indexFor(hash, table.length);Entry prev = table[i];Entry e = prev;while (e != null) {Entry next = e.next;Object k;if (e.hash == hash &&((k = e.key) == key || (key != null && key.equals(k)))) {modCount++;size--;if (prev == e)table[i] = next;elseprev.next = next;e.recordRemoval(this);return e;}prev = e;e = next;}return e;}
删除操作,先计算指定key的hash值,然后计算出table中的存储位置,判断当前位置是否Entry实体存在,如果没有直接返回,若当前位置有Entry实体存在,则开始遍历列表 。定义了三个Entry引用,分别为pre, e ,next 。在循环遍历的过程中,首先判断pre 和 e 是否相等,若相等表明,table的当前位置只有一个元素,直接将table[i] = next = null。若形成了pre -> e -> next 的连接关系,判断e的key是否和指定的key 相等,若相等则让pre -> next ,e 失去引用 。
6、
public boolean containsKey(Object key) {return getEntry(key) != null;}final Entry getEntry(Object key) {int hash = (key == null) ? 0 : hash(key.hashCode());for (Entry e = table[indexFor(hash, table.length)];e != null;e = e.next) {Object k;if (e.hash == hash &&((k = e.key) == key || (key != null && key.equals(k))))return e;}return null;}
方法是先计算hash然后使用hash和table.取摸得到index值,遍历table[index]元素查找是否包含key相同的值 。
7、
public boolean containsValue(Object value) {if (value =http://www.kingceram.com/post/= null)return containsNullValue();Entry[] tab = table;for (int i = 0; i < tab.length ; i++)for (Entry e = tab[i] ; e != null ; e = e.next)if (value.equals(e.value))return true;return false;}
方法就比较粗暴了,就是直接遍历所有元素直到找到value,由此可见的方法本质上和普通数组和list的方法没什么区别,你别指望它会像那么高效 。
五、JDK 1.8的 改变 1、采用数组+链表+红黑树实现 。
在Jdk1.8中的实现方式做了一些改变,但是基本思想还是没有变得,只是在一些地方做了优化,下面来看一下这些改变的地方,数据结构的存储由数组+链表的方式,变化为数组+链表+红黑树的存储方式,当链表长度超过阈值(8)时,将链表转换为红黑树 。在性能上进一步得到提升 。