1. Entry类中需包含键值的hash值,防止resize时的重复计算;
  2. Map容量为2的整幂,可使用位操作取代取余操作提高效率;
  3. resize时需要将原table的桶内数据置null,利于垃圾回收;
  4. 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 实现总结的更多相关文章

  1. HashMap与TreeMap源码分析

    1. 引言     在红黑树--算法导论(15)中学习了红黑树的原理.本来打算自己来试着实现一下,然而在看了JDK(1.8.0)TreeMap的源码后恍然发现原来它就是利用红黑树实现的(很惭愧学了Ja ...

  2. HashMap的工作原理

    HashMap的工作原理   HashMap的工作原理是近年来常见的Java面试题.几乎每个Java程序员都知道HashMap,都知道哪里要用HashMap,知道HashTable和HashMap之间 ...

  3. 计算机程序的思维逻辑 (40) - 剖析HashMap

    前面两节介绍了ArrayList和LinkedList,它们的一个共同特点是,查找元素的效率都比较低,都需要逐个进行比较,本节介绍HashMap,它的查找效率则要高的多,HashMap是什么?怎么用? ...

  4. Java集合专题总结(1):HashMap 和 HashTable 源码学习和面试总结

    2017年的秋招彻底结束了,感觉Java上面的最常见的集合相关的问题就是hash--系列和一些常用并发集合和队列,堆等结合算法一起考察,不完全统计,本人经历:先后百度.唯品会.58同城.新浪微博.趣分 ...

  5. 学习Redis你必须了解的数据结构——HashMap实现

    本文版权归博客园和作者吴双本人共同所有,转载和爬虫请注明原文链接博客园蜗牛 cnblogs.com\tdws . 首先提供一种获取hashCode的方法,是一种比较受欢迎的方式,该方法参照了一位园友的 ...

  6. HashMap与HashTable的区别

    HashMap和HashSet的区别是Java面试中最常被问到的问题.如果没有涉及到Collection框架以及多线程的面试,可以说是不完整.而Collection框架的问题不涉及到HashSet和H ...

  7. JDK1.8 HashMap 源码分析

    一.概述 以键值对的形式存储,是基于Map接口的实现,可以接收null的键值,不保证有序(比如插入顺序),存储着Entry(hash, key, value, next)对象. 二.示例 public ...

  8. HashMap 源码解析

    HashMap简介: HashMap在日常的开发中应用的非常之广泛,它是基于Hash表,实现了Map接口,以键值对(key-value)形式进行数据存储,HashMap在数据结构上使用的是数组+链表. ...

  9. java面试题——HashMap和Hashtable 的区别

    一.HashMap 和Hashtable 的区别 我们先看2个类的定义 public class Hashtable extends Dictionary implements Map, Clonea ...

  10. 再谈HashMap

    HashMap是一个高效通用的数据结构,它在每一个Java程序中都随处可见.先来介绍些基础知识.你可能也知 道,HashMap使用key的hashCode()和equals()方法来将值划分到不同的桶 ...

随机推荐

  1. 修改Linux终端提示符颜色

    修改Linux终端提示符颜色 作者:Eric 微信:loveoracle11g [root@linux-node2 ~]# tail -1 .bashrc PS1='[\[\033[1;31m\]\u ...

  2. 初始Golang

    Golang初识 字节跳动也就是我们常说的今日头条 1.今日头条基于Go语言构建千亿级微服务的实践 今日头条当前后端服务超过80%的流量是跑在Go构建的服务上 微服务数量超过100个 高峰QPS超过7 ...

  3. java读取按行txt文件

    import java.io.BufferedReader; import java.io.FileInputStream; import java.io.InputStreamReader; pub ...

  4. hbase启动后子节点的regionserver不能启动

    启动hbase后,主节点的进程正常,但是子节点的regionserver进程会自动挂掉 然后我们看看子节点的情况 可以看到挂掉了 我们这样解决问题,先把hadoop目录下的这个两个文件放到hbase的 ...

  5. 锚点定位,jquery定位到页面指定位置

    jquery锚点定位 $('body,html').animate({scrollTop: $('#ter1').offset().top}, 500);#ter1是你要定位的id对象,500是0.5 ...

  6. 05-spark streaming & kafka

    1.如何消费已经被消费过的数据? 答:采用不同的group 2.如何自定义去消费已经消费过的数据? Conosumer.properties配置文件中有两个重要参数 auto.commit.enabl ...

  7. idea一个窗口开启多个项目

    在将旧项目重构为微服务架构时,建立了十几个新的项目,对于相互之间存在调用的微服务,开发时都要同时启动,一开始我开了好多个idea窗口,结果电脑卡的不行,后来发现原来可以将项目都放到同一个idea窗口进 ...

  8. python中使用tabula爬取pdf数据并导出表格

    Tabula是专门用来提取PDF表格数据的,同时支持PDF导出CSV.Excel格式. 首先安装tabula-py: tabula-py依赖库包括Java.pandas.numpy所以需要保证运行环境 ...

  9. rem 布局的闪现问题

    <script type="text/javascript"> var sizeRate = document.documentElement.clientWidth/ ...

  10. spring事务传播实现源码分析

    转载. https://blog.csdn.net/qpfjalzm123/article/details/83717367 本文只是对spring事务传播实现的流程进行简单的分析,如有不对之处请指出 ...