一、HashMap的数据结构
HashMap<String,String> map=new HashMap();
map.put("1","Kobe");
这两行代码表示数据已经在HashMap中存储完成。而这也引发了一个问题,数据如何才能在HashMap中高效地存储?
从这个问题出发,我们首先应该了解HashMap的底层数据结构。
HashMap:数组+链表[单向链表]+红黑树 JDK1.8
我们都知道的是HashMap是存储键值对(key,value)的容器,那么从上图来看在每个小格子中应当放入key还是value或者都存放呢?
如果大家看过源码就会知道,这里采用了一种面向对象的思想,将【key,value】封装起来
class Node{
private String key;
private String value;
}
由此可知,每一个小格子就是一个new Node,而如果要将他们具体实现出来,只需要在Node的基础上稍加改动即可。
Node[] table=new Node[24]; //表示数组
class Node{
private String key; //表示单项链表
private String value;
Node next;
}
class TreeNode entends Node{ //红黑树的伪码表示
parent;
left;
right;
}
二、hash函数和碰撞
当我们获取数据后,要将其存入到HashMap中,就需要确定key,value组成的Node对象在数组索引下标中的位置。
如果想要获取位置,就需要:
- 数组长度 length
- 得到一个整型数 [0 ---- length-1]
(1)我们首先可能想到用
Random.nextInt(length);
但是这样以来就会产生两个问题:
- 随机重复的可能性太大
- 查找时候没有依据
(2)鉴于这样的情况,hashCode就登场了:
- 得到整型数
int hash = key.hashCode() ——> 32位的0和1组成的整数
如果我们用一个例子来表示:“1”.hashCode 有可能会超过存储范围
- 控制这个整型数的范围
这时就需要控制整形的hash值的范围:hash%length = 需要的范围
但即便是这样,也会产生一定的问题。在hash = key.hashCode();中,如果key的值是31,47之类的数,在模16后(hash%16)得到的结果都是1,这样Node对象去到同一个位置的可能性会比较大,存储的资源就会大大被浪费。
要使index的结