HashMap存储格式
首先来看看HashMap的数据存储格式:
从本质上来说,hashMap实际上是一个数组,数组的每个元素称为一个Node,这个Node实际上是一个链表,每个对象的hash值经过一些处理作为数组的key,hashMap通过key定位到数组对应的位置。当两个对象的hash值相同的时候,就会在链表的next元素进行拓展。
源码
本文主要要实现hashMap的put、get、扩容方法;
基本代码架构:
public class MyHashMap<K,V> {
//数组的初始大小
static final int DEFAULR_INITIAL_CAPACITY=16;
//安全因子
static final float DEFAULT_LOAD_FACTOR = 0.75f;
//扩容因子
static final int DEFAULT_DITATATION_FACROT=2;
private int size = 0;
//数组元素
private Node<K,V> table[] = null;
public V put(){
return null;
};
public V get(){
return null;
}
//Map的大小
public int size(){
return this.size;
}
//提供hash算法,确定Node在数组中的位置
private int indexOf(Object o){
return 0;
}
//扩容方法
private void dilatation() {
}
public class Node<K,V> implements Entry<K, V>{
@Override
public K getKey() {
return null;
}
@Override
public V getValue() {
return null;
}
@Override
public V setValue(V value) {
return null;
}
}
}
关于构造
前面已经说过,数组的元素是由节点Node
private class Node<K,V> implements Entry<K, V>{
//Node在数组中的位置,根据对象的hash值确定
private int index;
private K key;
private V value;
//当hash值出现冲突以后,往链表中插入对象
private Node<K,V> next;
public Node(int index, K key, V value, Node<K, V> next) {
super();
this.index = index;
this.key = key;
this.value = value;
this.next = next;
}
@Override
public K getKey() {
return null;
}
@Override
public V getValue() {
return null;
}
@Override
public V setValue(V value) {
return null;
}
}
下面来看看HashMap的构造:
private Node<K,V> table[] = null;
//创建一个大小为默认值的数组
public MyHashMap() {
table = new Node[DEFAULR_INITIAL_CAPACITY];
}
hash算法indexOf方法实现:
//提供hash算法,确定Node在数组中的位置
public int indexOf(K key){
//与数组length-1取模,确定返回值不大于数组的length-1
return hash(key) % (table.length-1);
}
//让hash值无符号右移16位,缩小hash值
static final int hash(Object key) {
int h;
return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}
源码实现
put方法实现:
public V put(K key,V value){
//tab用来指向table,p当前数组位置的Node;
Node<K, V> tab[] = table;
Node<K,V> p;
int i = indexOf(key);
p = table[i];
if(p == null){
//如果数组的该位置没有元素
p = new Node<K, V>(i, key, value, null);
tab[i] = p;
return value;
}else{
//如果数组的该位置有元素
Node<K,V> e;//用于判断key是否相同,是否需要覆盖
if(p.index == indexOf(key)&&(p.key==key||key.equals(p.key))){
//key相同(这里我们可以看到map判断key是否相同需要他的hash值和equals都相同)
e = p;
}else{
//对p进行遍历
for(int count = 0 ; ; ++count){
if((e=p.next)==null){
//如果p链表没有后续元素
p.next = new Node<K,V>(indexOf(key), key, value, null);
break;
}
//如果链表中其他元素的key有相同的
if(e.index==indexOf(key)&&(e.key==key||e.key.equals(key))){
break;
}
//如果链表有后续元素,并且key和链表当前位置的元素key不用,将p指向p.next
p= e;
}
}
//key有覆盖的情况出现,将key对应的value进行覆盖处理
if(e!=null){
e.value = value;
return value;
}
//e==null则没有覆盖情况
size++;
if(size>DEFAULR_INITIAL_CAPACITY*DEFAULT_LOAD_FACTOR){
//扩容;
dilatation();
}
}
return value;
};
get方法实现:
public V get(K key){
Node<K,V> tab[] ; Node<K,V> e ;
tab = table;
int index = indexOf(key);
e = tab[index];
//该key没有值
if(e == null){
return null;
}else{
//遍历Node e
do {
//获取e的值
if(key==e.key||key.equals(e.key)){
return e.value;
}
} while ((e=e.next)!=null);
}
return null;
}
扩容方法dilatation
//扩容方法
private void dilatation() {
Node<K, V> oldNode[] = table;
int oldCount = table.length;
//将容量扩张到两倍
int newCount = oldCount*DEFAULT_DITATATION_FACROT;
Node<K, V> newNode[] = new Node[newCount];
table = newNode;
for(int i = 0 ; i < oldCount ; i++){
if(oldNode[i]!=null){
Node<K,V> e = oldNode[i];
Node<K,V> tmp = oldNode[i];
//给newNode赋值,修改Node的index值
int newIndex = indexOf(tmp.getKey());
do {
tmp.index = newIndex;
} while ((tmp=tmp.next)!=null);
newNode[newIndex] = e;
}
}
}