简单谈谈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 接口
按照惯例先谈谈最近情况,最近不是刚好跨年吗?看到很多人都在写年度总结,所以我也在写年度总结文章(其实之前我基本没有写过的,今年有点感触,也想记录一下),结果发现写起来有点多,之前还想着元旦前发出来,结 ...
随机推荐
- QTP 表格的导入导出异常信息 笔记
0 环境 系统环境:win7 1 操作 1.1 前言 与异常遍历结合 需要表格记录下来(读写) 代码大概跑了一下 若细节有错 请自行更改 1.2 导出 systemutil.Run "D:\ ...
- laravel中用到的ServiceProvide
路由 全局限制 如果你希望路由参数可以总是遵循正则表达式,则可以使用 pattern 方法.你应该在 RouteServiceProvider 的 boot 方法里定义这些模式: 1 2 3 4 5 ...
- mac搭建本地服务器
目录 基础部分 1234 启动服务器添加自定义文档到本地服务器查看自定义效果手机/其他电脑 访问本机服务器 说明:本地开发需要搭建本地服务器进行页面的调试,mac系统自带apache服务,本篇日志是针 ...
- [LC] 19. Remove Nth Node From End of List
Given a linked list, remove the n-th node from the end of list and return its head. Example: Given l ...
- python语法基础-基础-控制语句
############### if条件控制语句 ############### # 以下实例 x 为 0-99 取一个数,y 为 0-199 取一个数,如果 x>y 则输出 x,如 ...
- windows下面 apache 虚拟主机配置
<VirtualHost > ServerAdmin www.test2.com DocumentRoot "D:/PHP/Apache/htdocs/testSite2&quo ...
- FFT算法的verilog实现
首先需要明白傅里叶相关的基本知识:还是 借用这位英雄的文章,真心写的让人佩服不已http://blog.jobbole.com/70549/ 然后是卷积的理解http://blog.csdn.net/ ...
- hosts原理及作用
https://blog.csdn.net/qq_41356488/article/details/82190372 手机也可以修改hosts,但是需要root权限,百度
- 解决Eclipse和MyEclipsejava.lang.OutOfMemoryError Java heap space的错误
Eclipse和MyEclipse出现错误:java.lang.OutOfMemoryError: Java heap space的错误,很熟悉的错误信息,可咋就想不起来在哪里设JVM的参数啊.请看下 ...
- java的Junit单元测试
函数主要分为以下几类: 1.有固定返回值的.用assert 方法即可. 2.修改了状态. (1)修改了数据库中的数据.可以查询数据库(select 语句),看数据是否发生了改变. --原则上应该是用 ...