简易HashMap实现
为了更好的理解HashMap线程不安全的根源,这里提供了HashMap的简易实现:
package map.test;
import org.apache.commons.lang3.StringUtils; /**
* Author:yepei@meituan.com
* Date:2017/7/5
* Time:15:45
* ------------------------------------
* Desc:
*/
public class HashMp {
private transient Node[] entries;//数组
private transient float loadFactor;
private transient int size; public static void main(String[] args) {
HashMp map = new HashMp(2, 0.75f);
map.put(3, "A");
System.out.println(map);
map.put(5, "B");
map.put(7, "C");
map.put(11, "D");
map.put(9, "E");
map.put(12, "F");
map.put(17, "G");
map.put(22, "H");
map.put(24, "I");
map.put(25, "I");
System.out.println(map); String s1 = map.get(22);
String s2 = map.get(25);
String s3 = map.get(0);
} public HashMp(int capacity, float loadFactor) {
this.entries = new Node[capacity];
this.loadFactor = loadFactor;
} public HashMp() {
this(16, 0.75f);
} public String put(int key, String value) {
Node n = new Node(key, value);
//算Hash值,为简单起见,hash值
int i = n.getIndex(entries.length);
Integer thisKey = key;
//查找是否有重复: hashCode相等,且equals方法相等的
for (Node old = entries[i]; old != null; old = old.next) {
Integer oldKey;
//hash相同,且equals返回true,证明有重复值插入,直接替换掉旧值
if (old.getHash() == n.getHash() && ((oldKey = old.key) == key || thisKey.equals(oldKey))) {
String oldValue = old.value;
old.value = value;//替换成新值
return oldValue;//返回旧值
}
}
//该key不存在,需要增加一个结点
addEntry(n);
return null;
} public String get(int key) {
int idx = new Node(key, null).getIndex(entries.length);
Integer thisKey = key;
//查找是否有重复: hashCode相等,且equals方法相等的
for (Node old = entries[idx]; old != null; old = old.next) {
Integer oldKey = old.key;
if (thisKey == oldKey || thisKey.equals(oldKey)) {
return old.value;
}
}
return null;
} private void addEntry(Node n) {
int oldLen = entries.length;
int targetIdx = n.getIndex(oldLen);
n.next = entries[targetIdx];
entries[targetIdx] = n;//插入到链首
if (size++ >= oldLen * loadFactor) {
resize(2 * oldLen);
}
} private void resize(int newCapacity) {
Node[] old = entries;
Node[] newMap = new Node[newCapacity];
for (int j = 0; j < old.length; j++) {
Node e = old[j];
if (e == null) {
continue;
}
old[j] = null;//老表中的元素置为Null //注意:该过程会将同一个bucket中的元素逆置,因为总是将元素插在了新表的头部。
//但不是就地逆置,因为将元素逐个copy到了新的链表中
do {
Node next = e.next;//暂存尾链表(去掉head的链表)
int i = e.getIndex(newCapacity);//得到将在新表中存储的位置
e.next = newMap[i];//切断指针,重新指向新表的表头(可能为null)
newMap[i] = e;//将e插入到新链表头部
e = next;//重新将e赋值为尾链表的头,对尾链表继续“切断指针,插入新表头”
} while (e != null);
}
entries = newMap;
} @Override
public String toString() {
StringBuilder sb = new StringBuilder("[");
int i = 0;
for (Node n : entries) {
sb.append(i++).append("{").append(n).append("}, ");
}
return StringUtils.removeEnd(sb.toString(), ", ") + "]";
} static class Node {
int key;
String value;
Node next; Node(int key, String value) {
this.key = key;
this.value = value;
} int getIndex(int tableLength) {
return getHash() % tableLength;
} //为方便起见,hash值直接取该对象的key
int getHash() {
return key;
} @Override
public String toString() {
return "(" + key + "," + value + ")——>" + next;
}
}
}
参考
HashMap源码解读:http://www.xiaomager.com/category/program/java/hashmap
Hashcode生成原理:http://www.cnblogs.com/godtrue/p/6395098.html
HashMap存在的三大并发问题:https://my.oschina.net/xianggao/blog/393990
简易HashMap实现的更多相关文章
- HashMap内部结构及实现原理
简单介绍 在研究HashMap之前,我们先大概了解下其他数据结构在新增,查找等基础操作执行性能 数组:采用一段连续的存储单元来存储数据.对于指定下标的查找,时间复杂度为O(1):通过给定值进行查找,需 ...
- Java面试题之HashMap阿里面试必问知识点,你会吗?
面试官Q1:你用过HashMap,你能跟我说说它的数据结构吗? HashMap作为一种容器类型,无论你是否了解过其内部的实现原理,它的大名已经频频出现在各种互联网Java面试题中了.从基本的使用角度来 ...
- hashmap的简易实现,基本实现PUT GET
p.p1 { margin: 0; font: 12px Menlo; color: rgba(79, 118, 203, 1) } /*简易版的HASHMAP包括基本的GET PUT思想 * 从数 ...
- 【简易版】HashMap(增删改查)
1.HashMap概述 (1)首先HashMap是基于哈希表的Map接口实现的.另外HashMap中存储的数据是按照键值跟键值对的关系来进行存储的. (2)不同于ArrayList方法的是,Array ...
- 自己用HashMap来模拟一个Session缓存(简易版)
本文记录:Hibernate中一级缓存的特点. 一级缓存的细节什么操作会向一 1.级缓存放入数据 save,update,saveOrUpdate,load,get,list,iterate,lock ...
- 实现一个简易的HashMap
实现一个键的类型为int,值的类型为int的HashMap 输入一个T,表示操作次数: 之后每行接一个操作,可以包括插入.删除.修改.查询.清空.判断是否有这个键: 因为是刚学完随手敲的,所以功能粗糙 ...
- 【面向对象版】HashMap(增删改查)
前言: 关于什么是HashMap,HashMap可以用来做些什么,这些定义类的描述,请参照[简易版]HashMap(增删改查)的内容. 这章节主要是面向实例,直接进行HashMap(增删改查)的演示. ...
- Spring + iBatis 的多库横向切分简易解决思路
国内私募机构九鼎控股打造APP,来就送 20元现金领取地址:http://jdb.jiudingcapital.com/phone.html内部邀请码:C8E245J (不写邀请码,没有现金送)国内私 ...
- Android学习之路——简易版微信为例(二)
1 概述 从这篇博文开始,正式进入简易版微信的开发.深入学习前,想谈谈个人对Android程序开发一些理解,不一定正确,只是自己的一点想法.Android程序开发不像我们在大学时候写C控制台程序那样, ...
随机推荐
- Linux中目录proc/net/dev详解
在Linux系统中,系统调用是操作系统提供给应用程序使用操作系统服务的重要接口,但同时也正是通过系统调用机制,操作系统屏蔽了用户直接访问系统内核的可能性.幸运的是Linux提供了LKM机制可以使我们在 ...
- openvswitch datapath 内核态流表创建过程(ovs_flow_cmd_new)
datapath流表更新的入口函数都定义在dp_flow_genl_ops中,流表创建的入口函数是ovs_flow_cmd_new函数,通过该函数,我们可以一窥流表相关信息的建立. 1.ovs_flo ...
- AVL树的实现——c++
一.概念 AVL树是根据它的发明者G.M. Adelson-Velsky和E.M. Landis命名的.它是最先发明的自平衡二叉查找树,也被称为高度平衡树.相比于"二叉查找树",它 ...
- ZZNU 1719(最长上升子序列+最长下降子序列)
先吐血一发,噗! 再吐血一次,啊啊啊啊! 好吧,做了那么多次最长上升子序列,看这题看了半天才发现还有最长下降子序列,呵呵哒! AC代码: #include<stdio.h>//老恶心#in ...
- 程序猿的日常——Java基础之抽象类与接口、枚举、泛型
再次回顾这些基础内容,发现自己理解的又多了一点.对于一些之前很模糊的概念,渐渐的清晰起来. 抽象类与接口 抽象类通常是描述一些对象的通用方法和属性,并且默认实现一些功能,它不能被实例化.接口仅仅是描述 ...
- css字体中英速查表
例1(小米米官网):font-family: "Arial","Microsoft YaHei","黑体","宋体",s ...
- Python小白学习之路(五)—【类和对象】【列表】【列表相关功能】
类和对象 (简单的了解一下这个概念,初步有个印象,这个概念很重要,后面会着重讲) 类:具有相同属性和方法的对象的集合: 对象:万物皆对象: 概念很抽象(每当我看不到概念的时候,我就会通过举例来理解) ...
- linux centos7 防火墙及端口开放相关命令
一.防火墙相关命令 1.查看防火墙状态 : systemctl status firewalld.service 注:active是绿的running表示防火墙开启 2.关闭防火墙 :systemct ...
- 获取列表数据时,getList 设置默认参数:getList(page = 1),点击分页及前往时,传page参数,其他使用page的默认值:1
获取列表数据时,getList 设置默认参数:getList(page = 1),点击分页及前往时,传page参数,其他使用page的默认值:1
- (转)MYSQL线程池总结(一)
MYSQL线程池总结(一) 原文:http://www.cnblogs.com/cchust/p/4510039.html 线程池是Mysql5.6的一个核心功能,对于服务器应用而言,无论是web应 ...