Java的HashMap实现原理整理总结
通过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实现原理整理总结的更多相关文章
- 【JAVA】HashMap的原理及多线程下死循环的原因
		
再次翻到以前工作中遇到的一个问题,HashMap在多线程下会出现死循环的问题,以前只是知道会死循环,导致CPU100%把机器拖跨,今天来彻底看看 首先来看下,HashMap的原理:HashMap是一个 ...
 - Java面试& HashMap实现原理分析
		
1. HashMap的数据结构 数据结构中有数组和链表来实现对数据的存储,但这两者基本上是两个极端. 数组 数组存储区间是连续的,占用内存严重,故空间复杂的很大.但数组的二分查找时间复杂度小,为O( ...
 - 详解 Java 8 HashMap 实现原理
		
HashMap 是 Java 开发过程中常用的工具类之一,也是面试过程中常问的内容,此篇文件通过作者自己的理解和网上众多资料对其进行一个解析.作者本地的 JDK 版本为 64 位的 1.8.0_171 ...
 - 1.Java集合-HashMap实现原理及源码分析
		
哈希表(Hash Table)也叫散列表,是一种非常重要的数据结构,应用场景及其丰富,许多缓存技术(比如memcached)的核心其实就是在内存中维护一张大的哈希表,而HashMap的实现原理也常常 ...
 - 【Java】HashMap实现原理---数据结构
		
作为一个程序猿,特别是Java后端的,应该全部人都用过HashMap,也都知道HaspMap是一个用于存储Key-Value键值对的集合.与此同时我们把每一个键值对也叫做 Entry. 而这些Entr ...
 - Java中HashMap实现原理
		
类声明: 概述: 线程不安全: <Key, Value>两者都可以为null: 不保证映射的顺序,特别是它不保证该顺序恒久不变: HashMap使用Iterator: HashMap中ha ...
 - Java中HashMap的实现原理
		
最近面试中被问及Java中HashMap的原理,瞬间无言以对,因此痛定思痛觉得研究一番. 一.Java中的hashCode和equals 1.关于hashCode hashCode的存在主要是用于查找 ...
 - HashMap的原理与实  无锁队列的实现Java HashMap的死循环 red black tree
		
http://www.cnblogs.com/fornever/archive/2011/12/02/2270692.html https://zh.wikipedia.org/wiki/%E7%BA ...
 - java 关于 hashmap 的实现原理的测试
		
网上关于HashMap的工作原理的文章多了去了,所以我也不打算再重复别人的文章.我就是有点好奇,我怎么样能更好的理解他的原理,或者说使用他的特性呢?最好的开发就是测试~ 虽说不详讲hashmap的工作 ...
 
随机推荐
- 用Collections.synchronizedCollection创建线程安全的集合、列表。。。
			
Collection c=Collections.synchronizedCollection(new ArrayList()); List list=Collections.synchronized ...
 - AugularJS从入门到实践(三)
			
前 言 前端 AngularJS是为了克服HTML在构建应用上的不足而设计的.(引用百度百科) AngularJS使用了不同的方法,它尝试去补足HTML本身在构建应用方面的缺陷.Angu ...
 - 【python】字符排序
			
一.摘要 最近在做一个排序的东西,被python的字符串编码格式折腾了一会儿,总结下 二.排序 英文排序不用说,sort sorted 比较好,内部已经实现 主要是中文,方法是查表获取拼音再进行排序. ...
 - js一些重点知识总结(二)
			
第一部分:数据类型转换 1) 数据类型的种类: 数值型number.布尔型(true(1) /false (0)).字符串型(String).空类型(null)(object) 2) 数据类型自动转换 ...
 - Java中的24种设计模式与7大原则 (转)
			
一.创建型模式 1.抽象工厂模式(Abstract factory pattern): 提供一个接口, 用于创建相关或依赖对象的家族, 而不需要指定具体类.2.生成器模式(Builder patter ...
 - spring是什么,Spring能帮我们做什么
			
1. spring是什么? Spring是一个开源的轻量级Java SE(Java 标准版本)/Java EE(Java 企业版本)开发应用框架,其目的是用于简化企业级应用程序开发.应用程序是由一组相 ...
 - Java基础之TCP与UDP
			
OSI 7层参考模型 物理层 --> 数据链路层 --> 网络层 --> 传输层 --> 会话层 --> 表示层 --> 应用层 按此顺序称为拆包,反之为封包. T ...
 - 用vector实现dijkstra
			
#include <stdio.h> #include <string.h> #include <string> #include <vector> # ...
 - C# 将数据表导出到Excel通用方法
			
DataGrid dg = new DataGrid(); dg.DataSource = dt; dg.DataBind(); Response.Clear(); Response.Buffer = ...
 - Python爬虫从入门到放弃(二十一)之 Scrapy分布式部署
			
按照上一篇文章中我们将代码放到远程主机是通过拷贝或者git的方式,但是如果考虑到我们又多台远程主机的情况,这种方式就比较麻烦,那有没有好用的方法呢?这里其实可以通过scrapyd,下面是这个scrap ...