常用的HashMap到底是个什么结构
作者:互联网
0x00 前言
HashMap 是最常用的容器之一,应该没什么疑问了。可你到底了解他吗?网上已经有很多文章来总结 HashMap 了,我来写这篇,主要是为了记录自己阅读之后的一点点小感悟,如若有错误的地方,请大家指正。下文分析基于 jdk1.8
。
0x01 一句话介绍
HashMap 内部是一个 Node 类数组,每个节点存放对应的数据。
0x02 概述
先来介绍下 HashMap ,主要依据来自 HashMap 的注释(熟悉的同学可以直接跳过到0x03
部分)。
1、HashMap 实现了 Map 接口,拥有 Map 的所有操作,具有以下特点:
允许
null
的 key 和 value 。大致上,他和 HashTable 相同,但是 HashTable 是线程安全的,而 HashMap 非线程安全。出于此原因,HashMap 在性能上明显会优于 HashTable 。
不保证顺序,原因在于其内在的原理,他是根据 key 的 hash 值来计算位置的,所以,顺序自然是无法保证的了。(到底怎么算的,往下看。)
2、HashMap 的 get , put 在hash值比较均匀的情况下,操作都是常数级别的时间复杂度。一个非常重要的点是,capacity 不能设置太高,load factor 不能设置的太低。(这两个变量又是干嘛的呢,这里先卖个关子✧(≖ ◡ ≖✿)嘿嘿)。
3、因为他不是线程安全的,所以可以通过 Collections.synchronizedMap 来包装,从而变成一个线程安全的 Map。
4、拥有 fail-fast 特性。简单来说,就是在遍历的时候,发现元素被改变,就抛出异常。
0x03 解释几个变量
构造函数里面的 initialCapacity
这个参数的意思比较明显,就是初始的 Map 长度。默认是 16。
Node<K,V>[] table
Map 中真正存放元素的地方,可以看到他是一个 Node 数组。Node 结构比较简单,就是一个 key-value 组成的一个链表,其中还有 hash变量,和 next 变量。
float loadFactor
顾名思义,负载因子。默认值是0.75,是一个空间和时间上的权衡。具体怎么来的,可能是一个复杂的逻辑推算。
int threshold
阈值,Map 所能容纳的键值对数量。是根据 Map 中的数组长度*loadFactor计算出来的。看到这个,应该就可以想到,如果 loadFactor设置的太小,会有什么问题了。没错,如果设置太小,容量就会很小,导致空间上的一个浪费,大部分的位置都是空的,没有被充分利用。反之,如果设置太大,就会导致元素放置非常拥挤,查询起来效率就会变低。
0x04 方法分析
构造函数
HashMap 有好几个构造函数,来看一个比较重要的吧。
public HashMap(int initialCapacity, float loadFactor) { // 如果传递进来的初始化数组的大小小于0,就是不合法,直接抛异常。 if (initialCapacity < 0) throw new IllegalArgumentException("Illegal initial capacity: " + initialCapacity); // 如果大于最大的值,就让他等于最大值。 if (initialCapacity > MAXIMUM_CAPACITY) initialCapacity = MAXIMUM_CAPACITY; if (loadFactor <= 0 || Float.isNaN(loadFactor)) throw new IllegalArgumentException("Illegal load factor: " + loadFactor); this.loadFactor = loadFactor; // 根据 tableSizeFor 方法进行数组长度的对齐。 this.threshold = tableSizeFor(initialCapacity); } // 数组长度的对齐。 static final int tableSizeFor(int cap) { int n = cap - 1; // 经过以下的变化,数组的长度一定是2^n了。 n |= n >>> 1; // 1 n |= n >>> 2; // 2 n |= n >>> 4; // 3 n |= n >>> 8; // 4 n |= n >>> 16; // 5 return (n < 0) ? 1 : (n >= MAXIMUM_CAPACITY) ? MAXIMUM_CAPACITY : n + 1; }
在这里给方法tableSizeFor
举个
标签:Node,Map,常用,HashMap,到底,initialCapacity,线程,loadFactor 来源: https://blog.51cto.com/14288256/2388275