马上过年了,很感谢各位小老弟的关注哦。
2018年的jdk集合框架专栏还有一些没写完,这几天刚好赶一下,不能再拖了。前面的重写过ArrayList和LinkedList,有木有很有意思呀~ 如果觉得很有意思就对了,接下来我们来拜访下HashMap大爷。
咱们先来分析一下HashMap的数据结构,这里我画了一张图:
这个图其实很简单,但是实际实现起来就很麻烦了。
HashMap就是数组和链表的结合体,先是根据hash值找到Entry[ ]数组的索引,hash值相等的键值对将会存到同一个数组索引的位置上。然后再根据key值找链表的位置,对应的存到链表的表尾。
很简单有没有,HashMap就这样巧妙的利用了数组方便寻址的优点,也利用了链表方便删除和插入的优点。
我们可以这样理解,数组的作用是先确定一个大概的范围,这样就不用像数组一样,操作一个数,一定要遍历完。然后链表是在数组确定了位置的基础上细分,这样就在一定程度上大大提高了效率! 当然jdk8中,当链表长度大于8,链表会自动变成红黑树。
明人不说暗话,我们先来实现一下put()方法,上代码!!!
package Study.Collection;
/**
* <p>Description: 自定义一个HashMap
* 实现了put方法增加键值对,并解决了键重复的时候覆盖相应的节点</p>
* @author zhangyan
* @date 2019/1/28 20:07
*/
public class YanHashMap {
/**
* 位桶数组。bucket array
*/
Node2[] table;
/**
* 存放的键值对的个数
*/
int size;
/**
* 定义构造函数
*/
public YanHashMap() {
//长度一般定义成2的整数幂
table = new Node2[16];
}
/**
* put方法
* @param key
* @param value
*/
public void put(Object key, Object value) {
//定义了新的节点对象
Node2 newNode = new Node2();
newNode.hash = myHash(key.hashCode(), table.length);
newNode.key = key;
newNode.value = value;
newNode.next = null;
/**
* temp是对应hash值的节点
*/
Node2 temp = table[newNode.hash];
//正在遍历的最后一个元素
Node2 iterLast = null;
boolean keyRepeat = false;
if (temp == null) {
//此处数组元素为空,则直接将新节点放进去
table[newNode.hash] = newNode;
size++;
} else {
//此处数组元素不为空,则遍历对应链表,对链表进行操作
while (temp != null) {
//判断key如果重复,则覆盖
if (temp.key.equals(key)) {
keyRepeat = true;
//只是覆盖value即可,其他的值(hash,key,next)保持不变
temp.value = value;
//覆盖之后就不用遍历链表后面的节点
break;
} else {
//key不重复,则遍历下一个。
iterLast = temp;
temp = temp.next;
}
}
//没有发生key重复的情况,则添加到链表最后一个节点
if(!keyRepeat){
iterLast.next = newNode;
size++;
}
}
}
/**
* 返回Hash值
* @param v
* @param length
* @return
*/
public static int myHash(int v, int length) {
// System.out.println("hash in myHash:"+(v&(length-1))); //直接位运算,效率高
// System.out.println("hash in myHash:"+(v%(length-1))); //取模运算,效率低
return v & (length - 1);
}
//测试
public static void main(String[] args) {
YanHashMap m = new YanHashMap();
m.put(10, "aa");
m.put(20, "bb");
m.put(30, "cc");
//测试key值相同,覆盖value是否成功
m.put(20, "jiajia");
// 找几个hash值相等的数测试链表
// 测试hash值相同的情况下,形成链表是否成功
m.put(53, "gg");
m.put(69, "hh");
m.put(85, "kk");
System.out.println(m);
}
}
节点
public class Node2 {
int hash;
Object key;
Object value;
Node2 next;
}
当然这里还没有重写toString()方法,所以想查看集合中的数据,只能debug了
存入集合中的数据:
生成的链表: