简单谈谈HashMap
概述
面试Java基础,HashMap可以说是一个绕不过去的基础容器,哪怕其他容器都不问,HashMap也是不能不问的。
除了HashMap,还有HashTable跟ConcurrentHashMap,两个都是线程安全的哈希容器,但是HashTable是JDK1.0就有的容器,线程安全是通过synchronized关键字来实现的,而且锁住的是整个table对象,虽然线程安全,但是并发性能并不高。因此在JDK1.5里面并发大师Doug Lea操刀写了个ConcurrentHashMap,通过粒度更细的锁来实现更高的性能。
HashMap的历史
在不同版本的JDK中,HashMap是在不停优化的。
- 比如JDK1.6里面new HashMap时,开辟了内存空间,如果不使用,则浪费内存;JDK1.7里面改成了懒加载,new HashMap并没有开辟内存空间,节约了内存空间
- 1.8优化了hashCode算法:高16位异或(XOR)低16位 主要是为了增加扰动,减少碰撞几率
- 1.8里面优化了hash碰撞较多情况下的性能问题(链表长度限制为8,过长时请将链表转换为TreeNode(红黑树))
配置常量
static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // aka 16
static final int MAXIMUM_CAPACITY = 1 << 30;
static final float DEFAULT_LOAD_FACTOR = 0.75f;
static final int TREEIFY_THRESHOLD = 8;
static final int UNTREEIFY_THRESHOLD = 6;
static final int MIN_TREEIFY_CAPACITY = 64;
HashMap容器初始化的容量为16,默认负载因子为0.75,树化阈值为8,反树化阈值为6。
put流程
- 对key的hashCode()做hash运算,计算index;
- 如果没碰撞直接放到bucket里;
- 如果碰撞了,以链表的形式存在buckets后;
- 如果碰撞导致链表过长(大于等于TREEIFY_THRESHOLD),就把链表转换成红黑树(JDK1.8中的改动);
- 如果节点已经存在就替换old value(保证key的唯一性)
- 如果bucket满了(超过load factor*current capacity),就要resize。
get流程
- 对key的hashCode()做hash运算,计算index;
- 如果在bucket里的第一个节点里直接命中,则直接返回;
- 如果有冲突,则通过key.equals(k)去查找对应的Entry;
- 若为树,则在树中通过key.equals(k)查找,O(logn);
- 若为链表,则在链表中通过key.equals(k)查找,O(n)。
Hash算法
static final int hash(Object key) {
int h;
return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}
HashMap中可以存放key为null的值,放在首位。
将高16位与低16位异或运算,通过这样一个扰动函数,减小了hash冲突的概率。然后再通过这个hash值与数组的长度进行取模运算,决定这个键值对该放入哪个bin中。
(n - 1) & hash
这个算法是当bin为bull的时候,直接将Node放入table中;当扩容的时候,存在两种情况,要么放在原来的位置,要么往后移动原来的容量大小的位置,这时候使用的是下面这个算法:
e.hash & oldCap
如果得到的结果为零,则在原位置;反之,则将其向高位移动oldCap大小的位置。
拓展
String的Hash算法如下:
public int hashCode() {
int h = hash;
if (h == 0 && value.length > 0) {
char val[] = value;
for (int i = 0; i < value.length; i++) {
h = 31 * h + val[i];
}
hash = h;
}
return h;
}
String类中的hashCode计算方法还是比较简单的,就是以31为权,每一位为字符的ASCII值进行运算,用自然溢出来等效取模。
哈希计算公式可以计为s[0]31^(n-1) + s[1]31^(n-2) + ... + s[n-1]
那为什么以31为质数呢?
主要是因为31是一个奇质数,所以31*i=32*i-i=(i<<5)-i,这种位移与减法结合的计算相比一般的运算快很多。
简单谈谈HashMap的更多相关文章
- 谈谈HashMap与HashTable
谈谈HashMap与HashTable HashMap 我们一直知道HashMap是非线程安全的,HashTable是线程安全的,可这是为什么呢?先聊聊HashMap吧,想要了解它为什么是非线程安全的 ...
- 【转】简单谈谈python的反射机制
[转]简单谈谈python的反射机制 对编程语言比较熟悉的朋友,应该知道“反射”这个机制.Python作为一门动态语言,当然不会缺少这一重要功能.然而,在网络上却很少见到有详细或者深刻的剖析论文.下面 ...
- 简单谈谈Python中的几种常见的数据类型
简单谈谈Python中的几种常见的数据类型 计算机顾名思义就是可以做数学计算的机器,因此,计算机程序理所当然地可以处理各种数值.但是,计算机能处理的远不止数值,还可以处理文本.图形.音频.视频.网页等 ...
- 简单谈谈contextlib的使用
简单谈谈contextlib的使用 写在前面 做这件事的原因: 在看书的时候,我发现了有大佬们用contextlib管理上下文,真的很牛皮,但是百度了以下,每个大佬都写了很多很全很深刻,讲道理五花八门 ...
- java——HashMap的实现原理,自己实现简单的HashMap
数据结构中有数组和链表来实现对数据的存储,但是数组存储区间是连续的,寻址容易,插入和删除困难:而链表的空间是离散的,因此寻址困难,插入和删除容易. 因此,综合了二者的优势,我们可以设计一种数据结构-- ...
- 简单谈谈js中的MVC
MVC是什么? MVC是一种架构模式,它将应用抽象为3个部分:模型(数据).视图.控制器(分发器). 本文将用一个经典的例子todoList来展开(代码在最后). 一个事件发生的过程(通信单向流动): ...
- 谈谈HashMap线程不安全的体现
原文出处: Hosee HashMap的原理以及如何实现,之前在JDK7与JDK8中HashMap的实现中已经说明了. 那么,为什么说HashMap是线程不安全的呢?它在多线程环境下,会发生什么情况呢 ...
- 手写一个简单的HashMap
HashMap简介 HashMap是Java中一中非常常用的数据结构,也基本是面试中的"必考题".它实现了基于"K-V"形式的键值对的高效存取.JDK1.7之前 ...
- 简单谈谈网络抓包,特别是thrift 接口
按照惯例先谈谈最近情况,最近不是刚好跨年吗?看到很多人都在写年度总结,所以我也在写年度总结文章(其实之前我基本没有写过的,今年有点感触,也想记录一下),结果发现写起来有点多,之前还想着元旦前发出来,结 ...
随机推荐
- VB6制作的自定义ocx控件
下载后,解压缩,有一个TreeviewExplorer.ocx文件 在Excel的开发工具选项卡,点击插入ActiveX控件 VBA窗体,VB6窗体.VB.Net窗体都可以使用这个自定义控件的功能. ...
- 在SpringBoot中使用Junit测试
一:加入依赖 <dependency> <groupId>junit</groupId> <artifactId>junit</artifactI ...
- iOS火焰动画效果、图文混排框架、StackView效果、偏好设置、底部手势等源码
iOS精选源码 高性能图文混排框架,构架顺滑的iOS应用. 使用OpenGLE覆盖阿尔法通道视频动画播放器视图. 可选最大日期截至当日日期的日期轮选器ChooseDatePicker 简单轻量的图片浏 ...
- mpvue框架的小程序和H5同时开发
demo链接1.样式统一为了达到共用一套样式,采用px2rem-loader和px2rpx-loader进行代码的打包,细节如下: 由于UI设计图是在蓝湖上标注,宽度750,选择像素 PX 样式中直接 ...
- [LC] 24. Swap Nodes in Pairs
Given a linked list, swap every two adjacent nodes and return its head. You may not modify the value ...
- MOOC(7)- case依赖、读取json配置文件进行多个接口请求-封装mock(9)
封装mock # -*- coding: utf-8 -*- # @Time : 2020/2/12 8:51 # @File : mock_demo_9.py # @Author: Hero Liu ...
- MySQL 之全文索引
最近在复习数据库索引部分,看到了 fulltext,也即全文索引,虽然全文索引在平时的业务中用到的不多,但是感觉它有点儿意思,所以花了点时间研究一下,特此记录. 引入概念通过数值比较.范围过滤等就可以 ...
- JavaScript学习总结(五)原型和原型链详解
转自:http://segmentfault.com/a/1190000000662547 私有变量和函数 在函数内部定义的变量和函数,如果不对外提供接口,外部是无法访问到的,也就是该函数的私有的变量 ...
- PowerDesign15连接数据库并反向表结构详细
10.0 sql2008 11.0 sql2010 这的服务器名称,复制到上面 这里的默认数据库不要改.Powerdesign会把自已的数据也存在默认的数据库里 一般不用改 测试 成功 这里ODBC的 ...
- Java IO: 异常处理
原文链接 作者:Jakob Jenkov 译者: 李璟(jlee381344197@gmail.com) 流与Reader和Writer在结束使用的时候,需要正确地关闭它们.通过调用close()方法 ...