HashMap是Map接口的实例化,存放<key,value>。
特点:
1.其中键值对的key值是唯一的,value的值是可以重复的。
2.在插入键值对时,key不能为空,否则就会抛出NullPointerException异常,但是value可以为空。
3.HashMap中键值对的key不能直接修改,value可以修改,如果要修改key,只能先将该key删除掉,然后再来进行重新插入。
底层实现:jdk1.7 链表+数组 jdk1.8以后 链表+数组+红黑树
HashMap通过key的HashCode经过扰动函数处理后得到Hash值,然后通过位运算判断当前元素存放的位置,如果位置存放元素的话,就判断元素与要存入的元素的hash值以及key是否相同,如果相同,直接覆盖,如果不同就通过拉链法解决冲突。当Map当中的元素总数超过Entry数组的0.75时,触发扩容操作,为减少链表长度,元素分配的更均匀。
HashMap
基于哈希思想,实现对数据的读写。当我们将键值对传递给
put()
方法时,它调用键对象的 hashCode()方法来计算
hashcode
,然后后找到
bucket
位置来储存值对象。当获取对象时,通过键对象 的equals()
方法找到正确的键值对,然后返回值对象。
HashMap使用链表来解决碰撞问题,当发生碰撞了,对象将会储存在链表的下一个节点中。
HashMap
在每个 链表节点中储存键值对对象。当两个不 同的键对象的hashcode
相同时,它们会储存在同一个
bucket
位置的链表中,可通过键对象的
equals() 方法用来找到键值对。如果链表大小超过
阈 值( 8)
,链表就会被改造为树形结构。
resize
解决多次扩容后数据分配问题。
HashMap的初始容量为
16,扩容每次都是
2的n次幂。
加载因子为0.75,当Map中元素总数超过Entry数组的0.75,就会触发扩容操作。
具体实现:
class HashNode{
public int key;
public int value;
HashNode next;
public HashNode(int key,int value){
this.key=key;
this.value=value;
}
}
public class MyHashMap {
private HashNode[] array=new HashNode[16];
private int size=0;
private int hashCode(int key){
return key%array.length;
}
public void put(int key,int value){
int index=hashCode(key);
for (HashNode cur=array[index];cur!=null;cur=cur.next){
if (cur.key==key){
cur.value=value;
return ;
}
}
HashNode newNode=new HashNode(key,value);
newNode.next=array[index];
array[index]=newNode;
size++;
if (loadFactor()>0.75){
resize();
}
}
private double loadFactor() {
return (double)size/array.length;
}
private void resize() {
HashNode[] newArray=new HashNode[array.length*2];
for (int i=0;i< array.length;i++){
HashNode next=null;
for (HashNode cur=array[i];cur!=null;cur=next){
next=cur.next;
int newIndex=cur.key%newArray.length;
cur.next=newArray[newIndex];
newArray[newIndex]=cur;
}
}
}
public Integer get(int key){
int index=hashCode(key);
for (HashNode cur=array[index];cur!=null;cur=cur.next){
if (cur.key==key){
return cur.value;
}
}
return null;
}
}