HashMap底层原理及简单实现

HashMap可以用键值对来存储对象,所谓键值对,就是可以通过对象来寻找对象,是对数组索引的推广。

底层原理

存储结构

HashMap底层的实现采用了哈希表,基本结构是“数组+链表”。HashMap里面有一个叫table的Entry数组,Entry是一个用作链表节点的类,也就是说,数组的每个元素都对应着一个链表,结构如图所示:
在这里插入图片描述

存储过程

在这里插入图片描述

当调用HashMap的put方法时

  • 首先,会计算key对象的哈希码,也就是调用它的hashcode()方法,一般是根据地址求出的。
  • 然后,通过特定的算法计算出哈希码对应在 [0,数组长度-1) 区间内的哈希值,例如图中是让哈希码模16,求出对应的哈希值是15;
  • 最后在table数组对应位置的链表中添加value对象(在添加的过程中会比较,将相同key值的对象覆盖掉)

注:两种最极端的计算哈希值算法:1.hashCode / hashCode 退化成一个链表 2.hashCode / 1退化成一个数组

注:为了提高效率,会将模运算换成位运算,当length是2的幂次时,hashCode & (length - 1)等效于hashCode % length

注:JDK8中,当链表长度大于8时,会将链表转化成一颗红黑树,提高查找效率

查找键值对过程

查找的过程类似于存储过程,只不过把存改为找到后返回。

  • 根据key值求出hashCode
  • 根据hashCode求出哈希值
  • 在table数组对应位置的链表中找到key值相同(equals)的节点,返回value对象
    注:equals为true,则hashCode必相同

扩容

当数组使用了四分之三的长度时,会进行扩容,扩容为原来长度的两倍,实质上是新定义一个两倍长度的数组,再进行数组拷贝。

简单实现

只是对HashMap的简单实现,许多情况并未考虑,仅仅是为了方便理解HashMap的两个核心方法:get()和put();

节点类

/**
 * 用于HashMap
 * TODO
 * @version 1.0
 * @author 王星宇
 */
class node<K,V>{
	int hash;
	K key;
	V value;
	node next;
}

变量及构造方法

node[] table; //位桶数组  buckey array
	int size;
	/**
	 * 构造方法 ,默认16(2的整数次幂)个
	 */
	myHashMap(){
		table = new node[16] ; // 2 的整数次幂
	}

计算哈希值

/**
	 * 计算v的哈希值
	 * @param key  key的hashCode
	 * @param length 数组长度
	 * @return v的哈希值
	 */
	public int myHash(int key,int length) {
		return key & (length - 1);
	}

重写toString()方法

/**
	 * 重写toString方法
	 */
	@Override
	public String toString() {
		StringBuffer SB = new StringBuffer("[");
		for(int i = 0;i < table.length;i++) {
			node temp = table[i];
			while(temp != null) {
				SB.append(temp.key + "=" + temp.value + ",");
				temp = temp.next;
			}
		}
		SB.setCharAt(SB.length() - 1, ']');
		
		return SB.toString();
	}

*put()方法

/**
	 * 存放键值对,未考虑数组扩容
	 * @param key 
	 * @param value
	 */
	public void put(K key,V value) {
		node newNode = new node();
		newNode.hash = myHash(key.hashCode(),table.length);
		newNode.key = key;
		newNode.value = value;
		newNode.next = null;
		
		node temp = table[newNode.hash];
		node last = null;//链表最后一个节点
		if(temp == null) {
			table[newNode.hash] = newNode;
			size++;
		}else {
			while(temp != null) {
				if(temp.key.equals(key)) {
					temp.value = value;
					break;
				}else {
					last = temp;	
					temp = temp.next;
				}
			}
			if(temp == null) {
				last.next = newNode;
				size++;
			}
		}
	}

get()方法

public V get(K key) {
		int hash = myHash(key.hashCode(),table.length);
		V value = null;
		
		if(table[hash] != null) {
			node temp = table[hash];
			while(temp != null) {
				if(temp.key.equals(key)){
					value = (V)temp.value;
					break;
				}
				temp = temp.next;
			}
		}
		
		return value;
	}
	

全部代码

package myCollection;
/**
 * 测试HashMap
 * TODO
 * @version 1.0
 * @author 王星宇
 */
public class myHashMap <K,V>{
	node[] table; //位桶数组  buckey array
	int size;
	/**
	 * 构造方法 ,默认16(2的整数次幂)个
	 */
	myHashMap(){
		table = new node[16] ; // 2 的整数次幂
	}
	/**
	 * 存放键值对,未考虑数组扩容
	 * @param key 
	 * @param value
	 */
	public void put(K key,V value) {
		node newNode = new node();
		newNode.hash = myHash(key.hashCode(),table.length);
		newNode.key = key;
		newNode.value = value;
		newNode.next = null;
		
		node temp = table[newNode.hash];
		node last = null;//链表最后一个节点
		if(temp == null) {
			table[newNode.hash] = newNode;
			size++;
		}else {
			while(temp != null) {
				if(temp.key.equals(key)) {
					temp.value = value;
					break;
				}else {
					last = temp;	
					temp = temp.next;
				}
			}
			if(temp == null) {
				last.next = newNode;
				size++;
			}
		}
	}
	/**
	 * 计算v的哈希值
	 * @param key  key的hashCode
	 * @param length 数组长度
	 * @return v的哈希值
	 */
	public int myHash(int key,int length) {
		return key & (length - 1);
	}
	/**
	 * 重写toString方法
	 */
	@Override
	public String toString() {
		StringBuffer SB = new StringBuffer("[");
		for(int i = 0;i < table.length;i++) {
			node temp = table[i];
			while(temp != null) {
				SB.append(temp.key + "=" + temp.value + ",");
				temp = temp.next;
			}
		}
		SB.setCharAt(SB.length() - 1, ']');
		
		return SB.toString();
	}
	
	public V get(K key) {
		int hash = myHash(key.hashCode(),table.length);
		V value = null;
		
		if(table[hash] != null) {
			node temp = table[hash];
			while(temp != null) {
				if(temp.key.equals(key)){
					value = (V)temp.value;
					break;
				}
				temp = temp.next;
			}
		}
		
		return value;
	}
	
}
/**
 * 用于HashMap
 * TODO
 * @version 1.0
 * @author 王星宇
 */
class node<K,V>{
	int hash;
	K key;
	V value;
	node next;
}
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值