数组和链表都是存储一个对象,HashMap 存储数据是以 一对数据来存储,即键值对【key(对象)---->value(对象)】。
JDK1.8版本之前,HashMap的实现: 数组 + 链表;
JDK1.8版本之后,HashMap的实现: 数组 + 链表 / 二叉树(红黒树);
数组的默认大小是16,加载因子【DEFAULT_LOAD_FACTOR】默认值是0.75f,表示当数组容量达到75%,数组会被重新扩充。数组的最大容量是整数最大值的一半。
HashMap存储数据结构中链表与二叉树的转化条件: 是键值对的总数大于64,且
a.在扩容时,当哈希表中数组同一个位置的链表长度大于8时(阀值),那么会把链表转换成红黑树,来提高查询效率;
b.在扩容时,当哈希表中数组同一个位置的链表长度小于6时(阀值),那么会把红黑树转换成链表,来提高查询效率。
阀值为什么是8 和 6? (防抖)减少链表与二叉树之间的转换频率,避免影响性能。
哈希表:这个是因为存储数据的方式被称为哈希(算法),Object类中hashCode方法是一个本地方法:表示此方法的具体实现是由 C、C++来实现的,哈希值()。
同一个对象,我们要保证在运行期hashCode值是相同的,如果不同那么此对象在哈希表中会有内存泄露问题。
内存泄露:由于对象在运行过程中,hashCode不同,导致该对象在哈希表中无法找到。
哈希表存储数据的算法:通过计算key对象的hashCode值,来确认key对象在哈希表数组中的存储位置,目的是为了可以通过计算hash值快速的查找对象。同一个对象,hashCode值相同,不同的对象,hashCode可能相同,因为整数是有限的。
使用hashCode计算对象的hash值:return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16)。
怎么扩容?初始化大小?
a.在第一次put数据的时候初始化;
b.在put方法中实现,扩容算法是 oldCap << 1 表示乘于2;
c.每次扩容哈希表,会导致所有已存储的对象重新计算哈希值,存储到新的哈希表中(重新散列)。所以在hashMap中,对象所在的位置不保证永远不变(无序),重新散列会导致重新计算所有对象,消耗性能,在可预知的情况下,散列次数越少越好。
HashMap的优点与缺点?
优点:取值快,数据量越大越明显;
缺点:线程不安全,避免频繁散列(rehash)。合理的使用new HashMap<>(initialCapacity);初始容量,来减少散列。
参与评论
手机查看
返回顶部