通过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. 用Collections.synchronizedCollection创建线程安全的集合、列表。。。

    Collection c=Collections.synchronizedCollection(new ArrayList()); List list=Collections.synchronized ...

  2. AugularJS从入门到实践(三)

      前  言  前端    AngularJS是为了克服HTML在构建应用上的不足而设计的.(引用百度百科) AngularJS使用了不同的方法,它尝试去补足HTML本身在构建应用方面的缺陷.Angu ...

  3. 【python】字符排序

    一.摘要 最近在做一个排序的东西,被python的字符串编码格式折腾了一会儿,总结下 二.排序 英文排序不用说,sort sorted 比较好,内部已经实现 主要是中文,方法是查表获取拼音再进行排序. ...

  4. js一些重点知识总结(二)

    第一部分:数据类型转换 1) 数据类型的种类: 数值型number.布尔型(true(1) /false (0)).字符串型(String).空类型(null)(object) 2) 数据类型自动转换 ...

  5. Java中的24种设计模式与7大原则 (转)

    一.创建型模式 1.抽象工厂模式(Abstract factory pattern): 提供一个接口, 用于创建相关或依赖对象的家族, 而不需要指定具体类.2.生成器模式(Builder patter ...

  6. spring是什么,Spring能帮我们做什么

    1. spring是什么? Spring是一个开源的轻量级Java SE(Java 标准版本)/Java EE(Java 企业版本)开发应用框架,其目的是用于简化企业级应用程序开发.应用程序是由一组相 ...

  7. Java基础之TCP与UDP

    OSI 7层参考模型 物理层 --> 数据链路层 --> 网络层 --> 传输层 --> 会话层 --> 表示层 --> 应用层 按此顺序称为拆包,反之为封包. T ...

  8. 用vector实现dijkstra

    #include <stdio.h> #include <string.h> #include <string> #include <vector> # ...

  9. C# 将数据表导出到Excel通用方法

    DataGrid dg = new DataGrid(); dg.DataSource = dt; dg.DataBind(); Response.Clear(); Response.Buffer = ...

  10. Python爬虫从入门到放弃(二十一)之 Scrapy分布式部署

    按照上一篇文章中我们将代码放到远程主机是通过拷贝或者git的方式,但是如果考虑到我们又多台远程主机的情况,这种方式就比较麻烦,那有没有好用的方法呢?这里其实可以通过scrapyd,下面是这个scrap ...