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. 查看hbase中的中文

    python: print '\xE4\xB8\xAD\xE5\x9B\xBD\xE7\x9A\x84\xE4\xB8\x8A\xE5\x8D\x88'.decode('utf-8')

  2. MySql 引擎

    存储引擎: 存储引擎就是指表的类型以及表在计算机上的存储方式 它处于MySQL体系架构中Server端底层,是底层物理结构的实现,用于将数据以各种不同的技术方式存储到文件或者内存中,不同的存储引擎具备 ...

  3. Java动手及实验整理

    1   枚举类型 在Java中,枚举类型本质上其实就是一个类,枚举中的常量都是该枚举类型的实例.枚举类型是引用类型!枚举不属于原始数据类型,它的每个具体值都引用一个特定的对象.相同的值则引用同一个对象 ...

  4. SQL Server 2016:内存列存储索引

    作者 Jonathan Allen,译者 谢丽 SQL Server 2016的一项新特性是可以在“内存优化表(Memory Optimized Table)”上添加“列存储索引(Columnstor ...

  5. Oracle:Authid Current_User的使用

    我们知道,用户拥有的role权限在存储过程是不可用的.遇到这种情况,我们一般需要显式授权,如grant create table to usera;但这种方法太麻烦,有时候可能需要进行非常多的授权才能 ...

  6. lunix salt 用法

    红蜘蛛软件 c/s client  : 学生端是客户端 ,装了红蜘蛛客户端-学生端 server端: 教师机  ,装了红蜘蛛软件-教师端  教师机,只能管理,  教师机和学生机,相互通信,相互知道的情 ...

  7. Mac安装compass失败的原因

    之前一直用的windows电脑,突然间切换成mac,各种不习惯,刚开始的时候连文件夹都找不到,悲催…… 还好,熟悉了两天之后,基本上也能够操作了. 然后就是安装各种开发软件,由于个人习惯了使用sass ...

  8. wmware虚拟机的克隆

    VMware 支持两种类型的克隆:完整克隆 链接克隆 完整克隆是和原始虚拟机完全独立的一个拷贝,它不和原始虚拟机共享任何资源.可以脱离原始虚拟机独立使用. 链接克隆需要和原始虚拟机共享同一虚拟磁盘文件 ...

  9. UVA-10020-贪心

    题意:给你一些数轴上的线段,要求寻找出某些线段能够完全覆盖[0,M],并且取的线段数目最小. 解题思路: 贪心思路, 1.每个线段都有一个L和R,代表它的起点和终点,对于所有R <= 0 ,   ...

  10. 关于HTTP_USER_AGENT

    其实HTTP_USER_AGENT的内容获取的很详细 可以获取手机的型号 这个是我的手机用UC浏览器 访问获取的代码 Mozilla/5.0 (Linux; U; Android 7.1.1; zh- ...