跟我一起阅读Java源代码之HashMap(二)
上一节中实现的SimpleHashMap,没有解决冲突的问题,这一节我们继续深入
由于table的大小是有限的,而key的集合范围是无限大的,所以寄希望于hashcode散落,肯定会出现多个key散落在同一个数组下标下面,
因此我们要引入另外一个概念,将key和value同时存入table[index]中,即将key和value构成一个对象放在table[index],而且可能存放多个,他们的key对应的index相同,但是key本身不同
现在我们就该讨论以什么样的方式存储这些散落在同一个数组下标的元素
可以考虑数组?
也可以考虑链表存储
源码里面是用链表存储的,其实我也没明白这两种方式在这里有什么区别
,感觉无论在检索和存储上都是差不多的效率,
检索都是需要遍历的方式,而存储也可以是顺序的
那这个问题留给大家吧。
我们来实现链式存储的方式,首先定义一个链表数据结构Entry:
public class Entry<K, V> {
//存储key
final K key;
//存储value
V value;
//存储指向下一个节点的指针
Entry<K, V> next;
//存储key映射的hash
final int hash;
}
新的EntryHashMap实现方式
public class EntryHashMap<K, V> { transient Entry[] table; transient int size; public V put(K key, V value) {
//计算出新的hash
int hash = hash(key.hashCode());
//计算出数组小标i
int i = indexFor(hash, table.length);
//遍历table[i],如果table[i]没有与新加入的key相等的,则新加入
//一个value到table[i]中的entry,否则将新的value覆盖旧的value并返回旧的value
for (Entry<K, V> e = table[i]; e != null; e = e.next) {
Object k;
if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {
V oldValue = e.value;
e.value = value;
return oldValue;
}
}
addEntry(hash, key, value, i);
return null;
} public void addEntry(int hash, K key, V value, int bucketIndex) {
Entry<K, V> e = table[bucketIndex];
//将新的元素插入链表前端
table[bucketIndex] = new Entry<>(hash, key, value, e);
size++;
} /**
* 通过hash code 和table的length得到对应的数组下标
*
* @param h
* @param length
* @return
*/
static int indexFor(int h, int length) {
return h & (length - 1);
} /**
* 通过一定算法计算出新的hash值
*
* @param h
* @return
*/
static int hash(int h) {
h ^= (h >>> 20) ^ (h >>> 12);
return h ^ (h >>> 7) ^ (h >>> 4);
}
}
跟我一起阅读Java源代码之HashMap(二)的更多相关文章
- 跟我一起阅读Java源代码之HashMap(一)
最近闲的很,想和大家一起学习并讨论下Java的一些源代码以及其实现的数据结构, 不是什么高水平的东西,有兴趣的随便看看 1. 为什么要用Map,以HashMap为例 很多时候我们有这样的需求,我们需要 ...
- 跟我一起阅读Java源代码之HashMap(三)
上一节我们讲到了如何用散列和链表实现HashMap,其中有一个疑问今天已经有些答案了,为什么要用链表而不是数组 链表的作用有如下两点好处 1. remove操作时效率高,只维护指针的变化即可,无需进行 ...
- 源码阅读 - java.util.concurrent (二)CAS
背景 在JDK 5之前Java语言是靠synchronized关键字保证同步的,这会导致有锁 锁机制存在以下问题: (1)在多线程竞争下,加锁.释放锁会导致比较多的上下文切换和调度延时,引起性能问题. ...
- 使用eclipse阅读java源码
很多时候想要阅读java源代码(无论是jdk自带的,还在第三方的),但是我们使用的jar包都是编译好的class包,无法在eclipse中直接打开,此时需要下载源码包. 本文以查看HttpClient ...
- Java源代码之LinkedHashMap
Java源代码之LinkedHashMap 转载请注明出处:http://blog.csdn.net/itismelzp/article/details/50554412 一.LinkedHashMa ...
- 如何在Eclipse下查看JDK源代码以及java源代码阅读方法(转载)
不会看JDK源代码,相当于没学过Java. 网上不容易找到一篇帮助我解决了如何在Eclipse下查看JDK源代码 的文章. 核心提示:在Eclipse中查看JDK类库的源代码!!! 设置: 1.点 w ...
- java面试之Hashmap
在java面试中hashMap应该说一个必考的题目,而且HashMap 和 HashSet 是 Java Collection Framework 的两个重要成员,其中 HashMap 是 Map 接 ...
- JDK1.7.0_45源码阅读<java.lang.Boolean>
本文适合的人群 其实感觉写这个标题的内容没有必要,只要你觉得对你有帮助那么就适合你,对你没帮助那么就不适合你.毕竟我不是专业作者,但咱会尽力的.其实最重要的一点是我不希望浪费您宝贵时间. 简要把内容在 ...
- 全中国的省市县镇乡村数据获取以及展示java源代码
第一步.准备工作(数据源+工具): 数据源(截止目前最全面权威的官方数据):http://www.stats.gov.cn/tjsj/tjbz/tjyqhdmhcxhfdm/2013/ 爬取数据的工具 ...
随机推荐
- VB/C#获取资源Rources
VB.Net: My.Resources.ResourceManager.GetObject("data") C# Properties.Resources.文件名
- jquery之Ajax(一)
1. load( url, [data], [callback] ) :载入远程 HTML 文件代码并插入至 DOM 中. url (String) : 请求的HTML页的URL地址. data (M ...
- Code Signal_练习题_All Longest Strings
Given an array of strings, return another array containing all of its longest strings. Example For i ...
- Android 退出整个应用程序
我们在写android应用程序时,经常会遇到想退出当前Acitivity,或者直接退出应用程序.我之前的一般操作是按返回键,或者直接按home键直接返回,其实这两种操作都没有关闭当前应用程序,没有释放 ...
- HDU4336 Card Collector(期望 状压 MinMax容斥)
题意 题目链接 \(N\)个物品,每次得到第\(i\)个物品的概率为\(p_i\),而且有可能什么也得不到,问期望多少次能收集到全部\(N\)个物品 Sol 最直观的做法是直接状压,设\(f[sta] ...
- jQuery基础(鼠标事件,表单事件,键盘事件,自定义事件 篇)
1.jQuery鼠标事件之click与dbclick事件 方法一:$ele.click()(不带参数) <div id="test">点击触发<div&g ...
- android之画板功能之橡皮擦 画笔大小和画笔颜色
第一展示设置画笔颜色的功能,第二展示设置画笔大小的颜色,而第三则展示橡皮擦的功能,这节将图标颜色设置为了蓝色,并且,增加了最左边的按钮(其实,就是在gridview中多增加了一个item). 下面分别 ...
- maven 远程仓库、私服及镜像配置
maven仓库分类 本地仓库.远程仓库.远程仓库又有私服.中央仓库.其它公共库.中央仓库是maven自带的核心仓库. 仓库配置远程仓库可以配置多个,超级pom中定义的中央仓库 <reposito ...
- redis介绍(7)高级用法
redis的过期策略以及内存淘汰机制 分析:这个问题其实相当重要,到底redis有没用到家,这个问题就可以看出来.比如你redis只能存5G数据,可是你写了10G,那会删5G的数据.怎么删的,这个问题 ...
- Django 简单用户注册
项目名 macboy app名 t1 1.项目macboy urls.py from django.conf.urls import url, include urlpatterns = [ url( ...