HashMap 实现总结
- Entry类中需包含键值的hash值,防止resize时的重复计算;
- Map容量为2的整幂,可使用位操作取代取余操作提高效率;
- resize时需要将原table的桶内数据置null,利于垃圾回收;
- hash函数考虑数据高位的影响,可减少冲突。
public class MyHashMap<K, V> implements IMap<K, V> {
static final float DEFAULT_LOAD_FACTOR = 0.75f;
static final int DEFAULT_CAPACITY = 16;
Entry<K, V>[] table;
int size;
/**
* 装载因子
*/
float loadFactor;
/**
* 实际的容量
*/
int threshold;
public MyHashMap() {
this.loadFactor = DEFAULT_LOAD_FACTOR;
this.threshold = (int) (DEFAULT_CAPACITY * loadFactor);
table = new Entry[DEFAULT_CAPACITY];
}
public MyHashMap(int initialCapacity, float loadFactor) {
/**
* 缺少参数检查
*/
int capacity = 1;
while (capacity < initialCapacity) {
capacity <<= 1;
}
this.loadFactor = loadFactor;
this.threshold = (int) (capacity * loadFactor);
table = new Entry[capacity];
}
public MyHashMap(int initialCapacity) {
this(initialCapacity, DEFAULT_LOAD_FACTOR);
}
/**
* 算术右移,计入高位影响
*/
static int hash(int h) {
return h ^ (h >>> 20) ^ (h >>> 12) ^ (h >>> 7) ^ (h >>> 4);
}
@Override
public V put(K k, V v) {
if (k == null) {
putForNull(v);
}
int hash = hash(k.hashCode());
int i = indexFor(hash, table.length);
for (Entry<K, V> e = table[i]; e != null; e = e.next) {
if (e.key.hashCode() == k.hashCode()
&& (e.key == k || (k != null && k.equals(e.key)))) {
V oldValue = e.value;
e.value = v;
return oldValue;
}
}
addEntry(k, v, i);
return null;
}
private void addEntry(K k, V v, int index) {
Entry<K, V> e = new Entry<K, V>(k, v, table[index]);
table[index] = e;
if (size++ > threshold) {
resize(table.length * 2);
}
}
void resize(int newCapacity) {
Entry[] newTable = new Entry[newCapacity];
transfer(newTable);
table = newTable;
threshold = (int) (newCapacity * loadFactor);
System.out.println("resize()" + " current capacity: " + table.length);
}
void transfer(Entry[] newTable) {
for (int i = 0; i < table.length; i++) {
Entry<K, V> e = table[i];
if (e != null) {
/**
* 需要將原table置为空,方可释放内存
*/
table[i] = null;
do {
Entry<K, V> next = e.next;
/**
* 重复计算hash值,效率不高
*/
int index = indexFor(hash(e.key.hashCode()),
newTable.length);
e.next = newTable[index];
newTable[index] = e;
e = next;
} while (e != null);
}
}
}
private V putForNull(V value) {
// 未实现
return value;
}
/**
* 用位操作取代取余操作,前提是数组长度为2的幂次
*/
private int indexFor(int hash, int length) {
return hash & (length - 1);
}
@Override
public V get(K k) {
int hash = hash(k.hashCode());
int index = indexFor(hash, table.length);
Entry<K, V> e = table[index];
while (e != null) {
if (e.key.hashCode() == k.hashCode()
&& (e.key == k || (k != null && k.equals(e.key)))) {
return e.value;
}
e = e.next;
}
return null;
}
static class Entry<K, V> {
K key;
V value;
Entry<K, V> next;
int hash;
public Entry(K k, V v, Entry<K, V> n) {
key = k;
value = v;
next = n;
// hash = h;
}
public V setValue(V v) {
V oldValue = value;
value = v;
return oldValue;
}
public boolean equals(Object o) {
if (!(o instanceof MyHashMap.Entry)) {
return false;
}
Entry e = (Entry) o;
Object k1 = e.key;
Object k2 = key;
if (k1 == k2 || (k1 != null && k1.equals(k2))) {
Object v1 = e.value;
Object v2 = value;
if (v1 == v2 || (v1 != v2 && v2.equals(v2))) {
return true;
}
}
return false;
}
}
}
HashMap 实现总结的更多相关文章
- HashMap与TreeMap源码分析
1. 引言 在红黑树--算法导论(15)中学习了红黑树的原理.本来打算自己来试着实现一下,然而在看了JDK(1.8.0)TreeMap的源码后恍然发现原来它就是利用红黑树实现的(很惭愧学了Ja ...
- HashMap的工作原理
HashMap的工作原理 HashMap的工作原理是近年来常见的Java面试题.几乎每个Java程序员都知道HashMap,都知道哪里要用HashMap,知道HashTable和HashMap之间 ...
- 计算机程序的思维逻辑 (40) - 剖析HashMap
前面两节介绍了ArrayList和LinkedList,它们的一个共同特点是,查找元素的效率都比较低,都需要逐个进行比较,本节介绍HashMap,它的查找效率则要高的多,HashMap是什么?怎么用? ...
- Java集合专题总结(1):HashMap 和 HashTable 源码学习和面试总结
2017年的秋招彻底结束了,感觉Java上面的最常见的集合相关的问题就是hash--系列和一些常用并发集合和队列,堆等结合算法一起考察,不完全统计,本人经历:先后百度.唯品会.58同城.新浪微博.趣分 ...
- 学习Redis你必须了解的数据结构——HashMap实现
本文版权归博客园和作者吴双本人共同所有,转载和爬虫请注明原文链接博客园蜗牛 cnblogs.com\tdws . 首先提供一种获取hashCode的方法,是一种比较受欢迎的方式,该方法参照了一位园友的 ...
- HashMap与HashTable的区别
HashMap和HashSet的区别是Java面试中最常被问到的问题.如果没有涉及到Collection框架以及多线程的面试,可以说是不完整.而Collection框架的问题不涉及到HashSet和H ...
- JDK1.8 HashMap 源码分析
一.概述 以键值对的形式存储,是基于Map接口的实现,可以接收null的键值,不保证有序(比如插入顺序),存储着Entry(hash, key, value, next)对象. 二.示例 public ...
- HashMap 源码解析
HashMap简介: HashMap在日常的开发中应用的非常之广泛,它是基于Hash表,实现了Map接口,以键值对(key-value)形式进行数据存储,HashMap在数据结构上使用的是数组+链表. ...
- java面试题——HashMap和Hashtable 的区别
一.HashMap 和Hashtable 的区别 我们先看2个类的定义 public class Hashtable extends Dictionary implements Map, Clonea ...
- 再谈HashMap
HashMap是一个高效通用的数据结构,它在每一个Java程序中都随处可见.先来介绍些基础知识.你可能也知 道,HashMap使用key的hashCode()和equals()方法来将值划分到不同的桶 ...
随机推荐
- Linux下安装与卸载anaconda
安装:到安装文件夹的目录下输入 bash Anaconda3-4.1.1-Linux-x86_64.sh 卸载:输入
- 您无法登陆系统。原因可能是您的用户记录或所属的业务部门在Microoft Dynamics CRM中已被禁用
问题发生在CRM 4.0 上 1 用户所在办事处及办事处上级被禁用. 2 如果已经重新启用了,还是报这个错误. 可以把停用的办事处及相关下级再重新--停用--启用一次试试. 3 如果还是报错,查看是否 ...
- [SQL]用SQL语句断开某个数据库的所有活动连接
USE master go IF EXISTS ( SELECT * FROM dbo.sysobjects WHERE id = OBJECT_ID(N'[dbo].[P_KillConnectio ...
- (转)wsdl文件用SoapUI快速创建WebService,CXF生成客户端代码
原文地址:http://blog.csdn.net/fjekin/article/details/62234861 一.前言 最近项目接触到2C的很多接口,提供接口文档和WSDL文件,一开始测试接口都 ...
- Solr——Windows下部署Solr6.6.0至Tomcat8.5.28(一)
一.window 环境 solr 6.6.3 下载地址 http://archive.apache.org/dist/lucene/solr/ jdk 1.8 tomcat 8.5 本机tomc ...
- Spring获取application.properties
方法一:@Value获取属性值 首先在application.properties中添加属性值 app.name=MyApp app.description=${app.name} is a Spri ...
- ES6学习笔记<一> let const class extends super
学习参考地址1 学习参考地址2 ECMAScript 6(以下简称ES6)是JavaScript语言的下一代标准.因为当前版本的ES6是在2015年发布的,所以又称ECMAScript 2015:也 ...
- 24.纯 CSS 创作出平滑的层叠海浪特效
原文地址:https://segmentfault.com/a/1190000014895634 感想:这里的波浪只是侧面的,利用几个平面一部分弧旋转得到. HTML代码: <div class ...
- python中的get
get()根据键获取字典中的值,如果键不存在则返回一个默认值,默认值不填写则返回None 1 a = { 2 "name":"dlrb", 3 "ag ...
- nodeJs 资料
http://blog.csdn.net/binyao02123202/article/details/18811207 非常详细 http://www.runoob.com/nodejs/nodej ...