为了更好的理解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实现的更多相关文章

  1. HashMap内部结构及实现原理

    简单介绍 在研究HashMap之前,我们先大概了解下其他数据结构在新增,查找等基础操作执行性能 数组:采用一段连续的存储单元来存储数据.对于指定下标的查找,时间复杂度为O(1):通过给定值进行查找,需 ...

  2. Java面试题之HashMap阿里面试必问知识点,你会吗?

    面试官Q1:你用过HashMap,你能跟我说说它的数据结构吗? HashMap作为一种容器类型,无论你是否了解过其内部的实现原理,它的大名已经频频出现在各种互联网Java面试题中了.从基本的使用角度来 ...

  3. hashmap的简易实现,基本实现PUT GET

    p.p1 { margin: 0; font: 12px Menlo; color: rgba(79, 118, 203, 1) } /*简易版的HASHMAP包括基本的GET  PUT思想 * 从数 ...

  4. 【简易版】HashMap(增删改查)

    1.HashMap概述 (1)首先HashMap是基于哈希表的Map接口实现的.另外HashMap中存储的数据是按照键值跟键值对的关系来进行存储的. (2)不同于ArrayList方法的是,Array ...

  5. 自己用HashMap来模拟一个Session缓存(简易版)

    本文记录:Hibernate中一级缓存的特点. 一级缓存的细节什么操作会向一 1.级缓存放入数据 save,update,saveOrUpdate,load,get,list,iterate,lock ...

  6. 实现一个简易的HashMap

    实现一个键的类型为int,值的类型为int的HashMap 输入一个T,表示操作次数: 之后每行接一个操作,可以包括插入.删除.修改.查询.清空.判断是否有这个键: 因为是刚学完随手敲的,所以功能粗糙 ...

  7. 【面向对象版】HashMap(增删改查)

    前言: 关于什么是HashMap,HashMap可以用来做些什么,这些定义类的描述,请参照[简易版]HashMap(增删改查)的内容. 这章节主要是面向实例,直接进行HashMap(增删改查)的演示. ...

  8. Spring + iBatis 的多库横向切分简易解决思路

    国内私募机构九鼎控股打造APP,来就送 20元现金领取地址:http://jdb.jiudingcapital.com/phone.html内部邀请码:C8E245J (不写邀请码,没有现金送)国内私 ...

  9. Android学习之路——简易版微信为例(二)

    1 概述 从这篇博文开始,正式进入简易版微信的开发.深入学习前,想谈谈个人对Android程序开发一些理解,不一定正确,只是自己的一点想法.Android程序开发不像我们在大学时候写C控制台程序那样, ...

随机推荐

  1. Java基础学习篇---------多态

    一.多态性的理解 1.向上转型:子类为父类对象实例化,调用的一定是子类覆写的方法,他们之间找的是共性 2.向下转型:子类扩充了父类的某些功能,而父类中没有该功能,他们之间找的是特性 案例: Numbe ...

  2. python 简单搭建阻塞式单进程,多进程,多线程服务

    由于经常被抓取文章内容,在此附上博客文章网址:,偶尔会更新某些出错的数据或文字,建议到我博客地址 :  --> 点击这里 我们可以通过这样子的方式去理解apache的工作原理 1 单进程TCP服 ...

  3. udid iphone6 获取

    http://www.udidregistration.org/how-to-find-udid-of-iphone-6.html

  4. sublime text 给选中项插入编号

    #coding=utf-8 import datetime, getpass import sublime, sublime_plugin import re # 插数字 class InsertNu ...

  5. elasticsearch 导入基础数据并索引之 geo_point

    elasticsearch 中的地理信息存储, 有geo_point形式和geo_shape两种形式 此篇只叙述geo_point, 地理位置需要声明为特殊的类型, 不显示在mapping中定义的话, ...

  6. 【bug】使用微信分享SDK,配置成功但分享信息异常

    使用微信JSD做H5分享功能时,显示配置成功,但分享出去的信息并不是配置中的信息.(p.s. ios 分享后只有一个当前的链接,androd连分享的图标都没有), 最终找的的原因是:分享的链接中,参数 ...

  7. Python 去除列表中重复的元素

    Python 去除列表中重复的元素 来自比较容易记忆的是用内置的set l1 = ['b','c','d','b','c','a','a'] l2 = list(set(l1)) print l2 还 ...

  8. Java基础梳理(一)

    List和Set比较,各自的子类比较 对比一:Arraylist与LinkedList的比较 1.ArrayList是实现了基于动态数组的数据结构,因为地址连续,一旦数据存储好了,查询操作效率会比较高 ...

  9. iOS根据图片url获取尺寸

    可以在UIImage的分类中加入下面的代码,并且引入系统的ImageIO.framework /** 根据图片的url获取尺寸 @param URL url @return CGSize */ + ( ...

  10. Postman—添加断言和检查点

    前言 postman断言是JavaScript语言编写的,在postman客户端指定区域编写即可. 断言会在请求返回之后,运行,并根据断言的pass\fail情况体现在最终测试结果中. 一.断言步骤 ...