通过Debug 探寻Java-HashMap 实现原理:

一个简单的例子,代码如下,

测试方法 main:

     public static void main(String[] args) {

         KeyObj obj1 = new KeyObj("AAAA");
KeyObj obj2 = new KeyObj("BBBB");
KeyObj obj3 = new KeyObj("CCCCC");
KeyObj obj4 = new KeyObj("DDDDD"); HashMap<KeyObj, String> hashMap = new HashMap<KeyObj, String>();
hashMap.put(obj1, "aaaa");
hashMap.put(obj2, "bbbb");
hashMap.put(obj3, "ccccc");
hashMap.put(obj4, "ddddd"); System.out.println(hashMap.values()); }

KeyObj.java

 public class KeyObj {

     String keyStr;

     public KeyObj(String keyStr) {
super();
this.keyStr = keyStr;
} public String getKeyStr() {
return keyStr;
} public void setKeyStr(String keyStr) {
this.keyStr = keyStr;
}
  
@Override
    // 覆盖hashCode方法,使得key的单双数分别获得一致的hash值,方便测试
public int hashCode() {
if (keyStr.length() % 2 == 0) {
return 31;
}
return 95;
} @Override
public boolean equals(Object obj) {
KeyObj obj1 = (KeyObj) obj;
if (this.keyStr.equalsIgnoreCase(obj1.keyStr))
return true;
return false;
} }

运行测试方法main,Debug查看HashMap:

1.可以看到HashMap其实是有一个名称为table的Entry数组,我们使用HashMap的put方法,本质是把我们的Key-Value作为Entry对象放入到HashMap中。

2.HashMap的table数组初始大小为16.

3.为何我们put了4个对象却只使用了table[10] 与 table[14]?

查看put方法JDK代码:

     public V put(K key, V value) {
if (table == EMPTY_TABLE) {
inflateTable(threshold); // 3.1 table若为空创建table,16大小
}
if (key == null)
return putForNullKey(value); // 3.2 key若为空放入table[0]
int hash = hash(key); // 3.3 计算放入key的hash,值为调用KeyObj的hashcode方法,再hash
int i = indexFor(hash, table.length);
       // 3.4 计算当前put的Enrty在table数组中精确位置(int i),跟踪代码可以很容易看出:
       // 3.4.1 精确位置i是由key的hash值与table.length取模
for (Entry<K,V> e = table[i]; e != null; e = e.next) { // 3.5 遍历table[i]的Entry
Object k;
if (e.hash == hash && ((k = e.key) == key || key.equals(k))) { // 3.6 若put相同key的KeyObj,则替换旧值
V oldValue = e.value;
e.value = value;
e.recordAccess(this);
return oldValue;
}
} modCount++;
addEntry(hash, key, value, i);// 3.7 创建Entry,当前table[i]的首节点变为当前put节点Entry对象的next节点,注:JDK8之前每一个table[i]上的Entry使用单链表存储的
return null;
}

理解了put,查看HashMap的get方法就很简单了:

     public V get(Object key) {
if (key == null)
return getForNullKey();
Entry<K,V> entry = getEntry(key); return null == entry ? null : entry.getValue();
}

继续查看第四行getEntry方法:

     final Entry<K,V> getEntry(Object key) {
if (size == 0) {
return null;
} int hash = (key == null) ? 0 : hash(key);
for (Entry<K,V> e = table[indexFor(hash, table.length)]; // 找到table[i],并便利该位置节点
e != null;
e = e.next) {
Object k;
if (e.hash == hash &&
((k = e.key) == key || (key != null && key.equals(k)))) // 找到,返回
return e;
}
return null;
}

其他:

在put函数代码中有一个注释:

JDK8之前每一个table[i]上的Entry使用单链表存储的

一直到JDK7为止,HashMap的结构都是这么简单,基于一个数组以及多个链表的实现,hash值冲突的时候,就将对应节点以链表的形式存储。

这样子的HashMap性能上就抱有一定疑问,如果说成百上千个节点在hash时发生碰撞,存储一个链表中,那么如果要查找其中一个节点,那就不可避免的花费O(N)的查找时间,这将是多么大的性能损失。这个问题终于在JDK8中得到了解决。再最坏的情况下,链表查找的时间复杂度为O(n),而红黑树一直是O(logn),这样会提高HashMap的效率。

所以在JDK8中,当同一个hash值的节点数不小于8时,将不再以单链表的形式存储了,会被调整成一颗红黑树。

Java的HashMap实现原理整理总结的更多相关文章

  1. 【JAVA】HashMap的原理及多线程下死循环的原因

    再次翻到以前工作中遇到的一个问题,HashMap在多线程下会出现死循环的问题,以前只是知道会死循环,导致CPU100%把机器拖跨,今天来彻底看看 首先来看下,HashMap的原理:HashMap是一个 ...

  2. Java面试& HashMap实现原理分析

    1. HashMap的数据结构 数据结构中有数组和链表来实现对数据的存储,但这两者基本上是两个极端.  数组 数组存储区间是连续的,占用内存严重,故空间复杂的很大.但数组的二分查找时间复杂度小,为O( ...

  3. 详解 Java 8 HashMap 实现原理

    HashMap 是 Java 开发过程中常用的工具类之一,也是面试过程中常问的内容,此篇文件通过作者自己的理解和网上众多资料对其进行一个解析.作者本地的 JDK 版本为 64 位的 1.8.0_171 ...

  4. 1.Java集合-HashMap实现原理及源码分析

    哈希表(Hash  Table)也叫散列表,是一种非常重要的数据结构,应用场景及其丰富,许多缓存技术(比如memcached)的核心其实就是在内存中维护一张大的哈希表,而HashMap的实现原理也常常 ...

  5. 【Java】HashMap实现原理---数据结构

    作为一个程序猿,特别是Java后端的,应该全部人都用过HashMap,也都知道HaspMap是一个用于存储Key-Value键值对的集合.与此同时我们把每一个键值对也叫做 Entry. 而这些Entr ...

  6. Java中HashMap实现原理

    类声明: 概述: 线程不安全: <Key, Value>两者都可以为null: 不保证映射的顺序,特别是它不保证该顺序恒久不变: HashMap使用Iterator: HashMap中ha ...

  7. Java中HashMap的实现原理

    最近面试中被问及Java中HashMap的原理,瞬间无言以对,因此痛定思痛觉得研究一番. 一.Java中的hashCode和equals 1.关于hashCode hashCode的存在主要是用于查找 ...

  8. HashMap的原理与实 无锁队列的实现Java HashMap的死循环 red black tree

    http://www.cnblogs.com/fornever/archive/2011/12/02/2270692.html https://zh.wikipedia.org/wiki/%E7%BA ...

  9. java 关于 hashmap 的实现原理的测试

    网上关于HashMap的工作原理的文章多了去了,所以我也不打算再重复别人的文章.我就是有点好奇,我怎么样能更好的理解他的原理,或者说使用他的特性呢?最好的开发就是测试~ 虽说不详讲hashmap的工作 ...

随机推荐

  1. 如何制作一个完美的全屏视频H5

    写在前面的话: 最近一波H5广告火爆整个互联网圈,身为圈内人,我们怎能     不! 知!道! :( 嘘!真不知道的也继续看下去,有收获 ↓ ) So,搞懂这个并不难. 这篇文章将带你从头到尾了解H5 ...

  2. Mac系统下STF的环境搭建和运行

    本文参考以下文章整理:MAC 下 STF 的环境搭建和运行 一. 前言 STF,全称是Smartphone Test Farm,WEB 端批量移动设备管理控制工具,就是可以用浏览器来批量控制你的移动设 ...

  3. ARM开发(3)基于STM32的矩阵键盘控制蜂鸣器

    一 矩阵键盘控制蜂鸣器原理:  1.1 本实验实现8*7矩阵键盘上按键控制蜂鸣器响.  1.2 实验思路:根据电路图原理,找出矩阵键盘行列所对应的引脚,赋予对应的按键值,然后控制蜂鸣器响.  1.3 ...

  4. centos7 Mysql备份还原并下载到windos

    数据库备份 1.show databases; #查看一下数据库 2.对应数据库做备份开始: mysqldump -u root -p 需要备份的数据库 >  db.sql     #把它备份到 ...

  5. 灵玖软件NLPIRParser智能文本聚类

    随着互联网的迅猛发展,信息的爆炸式增加,信息超载问题变的越来越严重,信息的更新率也越来越高,用户在信息海洋里查找信息就像大海捞针一样.搜索引擎服务应运而生,在一定程度上满足了用户查找信息的需要.然而互 ...

  6. 银河英雄传说[NOI2002]

    题目描述 公元五八○一年,地球居民迁移至金牛座α第二行星,在那里发表银河联邦创立宣言,同年改元为宇宙历元年,并开始向银河系深处拓展.       宇宙历七九九年,银河系的两大军事集团在巴米利恩星域爆发 ...

  7. JavaScript高程--<script>标签

    <script>标签 在HTML5中script主要有以下几个属性:async,defer,charset,src,type, async(可选): 关键词:异步脚本,外部文件,立即下载: ...

  8. Typescript变量声明

    let 和 const 是 javascript 里面最新的变量声明方式,let 与 var 很相似,而 const 是 let 的增强,能阻止对一个变量的再次赋值. var 声明 弱类型:var 声 ...

  9. 1.初入GitHub

    进入github官网,点击右上角注册按钮.  填写账号名,邮箱和密码    选择免费的公开仓库,点击完成就提示注册成功了.   ps:付费一般是给企业用户使用的,用来存放一些不公开的代码.所以是付费的 ...

  10. nopCommerce 3.9 大波浪系列 之 微信公众平台登录插件

    一.简介 插件源码下载:点击下载 微信公众平台网站授权帮助地址:https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp142114084 ...