JDK1.7和1.8中hashmap的区别?

  1. 实现方式

jdk版本

数据结构

1.7

数组+链表

1.8

数组+链表+红黑树(节点数>=8并且数组 长度>=64转换为数组+红黑树)

  1. put方法
    JDK1.7用的是头插法,而JDK1.8及之后使用的都是尾插法(尾插法需要遍历链表),头插法速度较高,但这种插入方法在并发场景下如果多个线程同时扩容会出现循环列表。1.8之后,链表长度到8之后就变成红黑树了,遍历的效率变高,采用尾插法效率也没多大影响,同时红黑树接口也不存在头插法了。
  2. 扩容
    在JDK1.7的时候是先扩容后插入的,1.7只要容量达到阈值,并且桶中不为null,就进行扩容,但当key重复时,虽然桶中不为null,但实际上size还是没变,这样就发生了无效扩容;1.8是先插入再扩容的,如果插入的元素在桶中存在,则直接替换,并return,不会发生扩容,如果没有存在,不管hash有没有冲突,都插入后进行扩容;
    1.7:
//扩容条件:1、当前HashMap中Entry个数 >= threshold 2、要插入位置的链表不为空
if ((size >= threshold) && (null != table[bucketIndex])) {
//扩容,新数组的长度为原数组的2倍
resize(2 * table.length);
hash = (null != key) ? hash(key) : 0;
//扩容后需要重新计算index
bucketIndex = indexFor(hash, table.length);
}

1.8:

if (e != null) { // existing mapping for key
V oldValue = e.value;
if (!onlyIfAbsent || oldValue == null)
e.value = value;
afterNodeAccess(e);
//替换后直接return
return oldValue;
}
}
++modCount;
//扩容条件
if (++size > threshold)
resize();
afterNodeInsertion(evict);
return null;