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中/目录扩容
1:原来的系统20G,目前增加到30G,我要把增加的10G扩容到/目录下 2:fdisk /dev/sda (对sda这块磁盘没有被使用的空间进行分区,联想Windows操作系统) 使用L ...
- Mybatis 系列10-结合源码解析mybatis 的执行流程
[Mybatis 系列10-结合源码解析mybatis 执行流程] [Mybatis 系列9-强大的动态sql 语句] [Mybatis 系列8-结合源码解析select.resultMap的用法] ...
- 安装npm报错 npm cache clean --force 搞定
- Linux coredump 的打开和关闭
(转载自 http://blog.sina.com.cn/s/blog_6b3765230100lazj.html) ulimit -c 输出如果为0,则说明coredump没有打开 ulimit - ...
- Redis的集群模式
集群 即使使用哨兵,此时的Redis集群的每个数据库依然存有集群中的所有数据,从而导致集群的总数据存储量受限于可用存储内存最小的数据库节点,形成木桶效应.由于Redis中的所有数据都是基于内存存储,这 ...
- Android模块化开发、组件化开发;
模块化开发:优点嘛,项目过大时便于管理: 1.在根目录的gradle.properties文件下添加 isBuildModule=false: 使用isBuildModule来控制这个是Library ...
- css(层叠样式表)属性
CSS属性相关 宽和高 width属性可以为元素设置宽度. height属性可以为元素设置高度. 块级标签才能设置宽度,内联标签的宽度由内容来决定. 字体属性 文字字体 font-family可以把多 ...
- linux&php:ubuntu安装php-7.2
1.下载php源码,地址:http://www.php.net/downloads.php 这里下载的是tar.gz的包 2.解压安装 将安装包解压到/usr/local/php 安装C的编译工具 s ...
- vue搭配axios踩坑
客户端项目中有一个小需求“我的卡券”,有单独入口,所以综合考虑之后,采用了vue来实现,因为是初次使用,导致了选型不当,先用了SUI-Mobile来搭建页面,当决定使用vue的时候,页面也搭建完毕了, ...
- 《C++数据结构-快速拾遗》 手写链表
注释:吕鑫老师C++对于找工作真的是很好的教程,基本什么方面都讲的很细致,但是对于大多数人只有快进快进再快进~~ 注释:基本链表信息自己百度,这里只是一个快速拾遗过程. 1.链表定义 typedef ...