以JDK7为例子说明:
HashMap map = new HashMap();
在实例化后,底层创建了一个长度为16的一维数组Entry[] table。
/*可能执行过多次put*/
map.put(key1,value1);
- 首先调用key1所在类的hashCode() 计算key1的哈希值,此哈希值经过某种算法后,对应得到在Entry数组中的存放位置。如果此位置上的数据为空,此时key1-value1就添加成功。--->情况一
- 如果此位置上的数据不为空,(意味着此位置上存在一个或多个数据(以链表的形式存在)),比较key1和已经存在的一个或多个数据的哈希值:
- 如果key1的哈希值和已经存在的数据的哈希值都不相同,此时key1-value1添加成功。--->情况二
- 如果key1的哈希值和已经存在的某个数据(key2-value2)的哈希值相同,继续比较:调用key1所在类的equals()方法:
- 如果equals()返回false:此时key1-value1就添加成功。 ---> 情况三
- 如果equals()返回true:使用value1替换value2.
tip:
-
关于情况二和情况三:此时key1-value1和原来的数据以链表的方式储存。
-
关于map中判断对象是否相同,个人理解是只有当两个对象类型相同且各个字段均相同时,在map添加过程中才会被视为同一个对象,与地址无关(hashCode()的返回值不依赖于对象的地址)。
jdk 8 相较于 jdk 7 底层方面的不同:
-
1.new HashMap():底层没有创建一个长度为16的数组;
-
2.jdk 8 底层的数组是:Node[],而非Entry[]
-
3.首次调用put()方法时,底层创建长度为16的数组
-
当数组的某一个索引位置上的元素以链表的形式存在的个数 > 8 且当前数组的长度> 64时,此时此索引位置上的所有数据改为用红黑树存储。4.jdk7 底层结构只有:数组+链表。 jdk8 : 数组 + 链表 + 红黑树
DEFAULT_INITIAL_CAPACITY : HashMap的默认容量,16;
DEFAULT_LOAD_FACTOR:HashMap的默认加载因子 0.75
threshold:扩容的临界值,=容量*填充因子 : 16 * 0.75 = 12;
TREEIFY_THRESHOLD:Bucket中链表长度大于该默认值,转化为红黑树 8
MIN_TREEIFY_CAPACITY:桶中的Node被树化时最小的hash表容量。 64