HashMap

关于hash表的基础内容,请看文章

【数据结构-查找】3.散列表详解
【Java自顶向下】HashMap面试题(2021最新版)

顶层应用

public class HashMapTest {public static void main(String[] args) {HashMap<String, String> stringStringHashMap = new HashMap<>();// 1.put存储键值对stringStringHashMap.put("ffideal","宇定");stringStringHashMap.put("床前明月光","疑是地上霜");// 2.get利用key获取valueString name = stringStringHashMap.get("ffideal");System.out.println(name);// 3.containsKey是否存在某个键值if (stringStringHashMap.containsKey("ffideal")) {System.out.println("ffideal存在");} else {System.out.println("ffideal不存在");}// 4.replace修改key-valuestringStringHashMap.replace("ffideal","宇定2");String name3 = stringStringHashMap.get("ffideal");System.out.println(name3);// 5.遍历HashMap中的键值对Set<String> strings = stringStringHashMap.keySet();for (String s: strings) {System.out.println("遍历数据:" + s);}// 6.clear清空HashMap中的元素stringStringHashMap.clear();Set<String> strings2 = stringStringHashMap.keySet();for (String s: strings2) {System.out.println("清空后的数据" + s);}}
}

底层原理

put => key => HashCode => 位置index

get => key => HashCode => 位置index

问:HashMap数组大小初始值是多少?最大是多少?如果为给定初始值,初始大小是多少?

答:16(242^424);2302^{30}230;大于等于参数的最小2的幂次方

private static final int tableSizeFor(int c) {// 传入32或20int n = c - 1;// n=31或19n |= n >>> 1;n |= n >>> 2;n |= n >>> 4;n |= n >>> 8;n |= n >>> 16;// 此时n=31或31,最后经过两次判断后返回值为32return (n < 0) ? 1 : (n >= MAXIMUM_CAPACITY) ? MAXIMUM_CAPACITY : n + 1;
}

问:HashMap 在 Java 7 与Java 8 中底层的不同?

答:Java 7 中的HashMap的底层是一个数组+链表的设计,每个hash值的第一个值放在数组里,之后经过hash运算得到相同的hash值锁定数组下标,数组中的每一个元素都是一个单向链表(碰撞,列表)。

  1. capacity:当前数组容量,始终保持 2n2^n2n,可以扩容,扩容后数组大小为当前的 2 倍。
  2. loadFactor:负载因子,默认为 0.75。
  3. threshold:扩容的阈值,等于 capacity * loadFactor。

HashMap的数据插入原理

存储结构的变化

Java 8 中的HashMap的底层是数组+链表+红黑树的方式实现。

为什么要使用红黑树而不使用AVL树

红黑树牺牲了一些查找性能 但其本身并不是完全平衡的二叉树。因此插入删除操作效率略高于AVL树

AVL树用于自平衡的计算牺牲了插入删除性能,但是因为最多只有一层的高度差,查询效率会高一些。

改进的是在数据量较大的情况下(Java8 中,当链表中的元素超过了 8 个以后,会将链表转换为红黑树)单向链表的时间复杂是O(N),采用红黑树将时间复杂度降到O(logN)。

static final int TREEIFY_THRESHOLD = 8;

那么, 如果我们在删除容器中的元素的时候,删到多少才使得红黑树的存储结构转为链表呢?答案是6。

static final int UNTREEIFY_THRESHOLD = 6;

也就是说,在JDK8之后,创建HashMap对象=>添加数组中同一个位置元素超过8个=>该位置链表转为红黑树=>删除数组中同一个位置元素少于6个=>该位置红黑树转为列表。

最小树形化的策略

最小树形化容量阈值:即 当哈希表中的容量 > 该值时,才允许树形化链表 (即 将链表 转换成红黑树), 否则,若桶内元素太多时,则直接扩容,而不是树形化。为了避免进行扩容、树形化选择的冲突,这个值不能小于 4 * TREEIFY_THRESHOLD。

也就是说,当数组中某个桶中的元素大于8,数组容量小于64时,使用容量进行两倍扩容(其实就是用扩容代替链表转红黑树操作)。当数组中某个桶中的元素大于8且数组容量大于64时,链表转红黑树操作。

hashMap并不是在链表元素个数大于8就一定会转换为红黑树,而是先考虑扩容,扩容达到默认限制后才转换

hashMap的红黑树不一定小于等于6的时候就会转换为链表,而是只有在resize的时候才会根据 UNTREEIFY_THRESHOLD(6) 进行转换

HashMap怎么解决碰撞问题的?

Java中HashMap是利用“拉链法”处理HashCode的碰撞问题。

在调用HashMap的put方法或get方法时,都会首先调用hashcode方法,去查找相关的key,当有冲突时,再调用equals方法。

hashMap基于hasing原理,我们通过put和get方法存取对象。当我们将键值对传递给put方法时,他调用键对象的hashCode()方法来计算hashCode,然后找到bucket(哈希桶)位置来存储对象。

当获取对象时,通过键对象的equals()方法找到正确的键值对,然后返回值对象。

HashMap使用链表来解决碰撞问题,当碰撞发生了,对象将会存储在链表的下一个节点中。hashMap在每个链表节点存储键值对对象。当两个不同的键却有相同的hashCode时,他们会存储在同一个bucket位置的链表中。

键对象的equals()来找到键值对。

HashMap的一些特点

HashMap的5个特点
HashMap键不可重复,值可重复
底层hash表
具有很快的访问速度,遍历顺序不确定
线程不安全,若需要线程安全则需要使用Collections中的synchronizedMap方法来保障
允许key值为null,value值也为null

一些误区

问1:是否可以两个key值为null?

答1:不可以,后者会把前者覆盖

问2:HashMap插入时,使用头插法还是尾插法?

答2:在插入时采用尾插法(1.7是头插法),在并发场景下导致链表成环的问题。而在jdk1.8中采用尾插入法,在扩容时会保持链表元素原本的顺序,就不会出现链表成环的问题了。

头插法和尾插法

头插法带来的环状

一些不足和解决方式

HashMap不是线程安全的.

Java中有HashTable、Collections.synchronizedMap、以及ConcurrentHashMap可以实现线程安全的Map。

HashTable是直接在操作方法上加synchronized关键字,锁住整个数组,粒度比较大。因为synchronized关键字每次执行都会调用操作系统的锁来保证线程安全,也就是每次执行代码块,都要涉及 “用户态” 到 “内核态” 的转变,十分消耗资源。

Collections.synchronizedMap是使用 Collections集合工具的内部类,通过传入Map封装出一个SynchronizedMap对象,内部定义了一个对象锁,方法内通过对象锁实现。

ConcurrentHashMap使用分段锁,降低了锁粒度,让并发度大大提高我们一般都会使用HashTable或者ConcurrentHashMap,但是因为前者的并发度的原因基本上没啥使用场景了,所以存在线程不安全的场景我们都使用的是ConcurrentHashMap。

HashTable我看过他的源码,很简单粗暴,直接在方法上锁,并发度很低,最多同时允许一个线程访问,ConcurrentHashMap就好很多了,1.7和1.8有较大的不同,不过并发度都比前者好太多了

【Java自顶向下】面试官:HashMap源码看过吗?我:看过!面试官:好极了,那么来扒一扒吧!相关推荐

  1. Java类集框架 —— HashMap源码分析

    HashMap是基于Map的键值对映射表,底层是通过数组.链表.红黑树(JDK1.8加入)来实现的. HashMap结构 HashMap中存储元素,是将key和value封装成了一个Node,先以一个 ...

  2. java容器三:HashMap源码解析

    前言:Map接口 map是一个存储键值对的集合,实现了Map接口的主要类有以下几种 TreeMap:用红黑树实现 HashMap:数组和链表实现 HashTable:与HashMap类似,但是线程安全 ...

  3. HashMap源码解读(中篇)

    文章目录 前言 一.进入JDK中的源码(InteliJ IDEA为例) 二.HashMap的结构 三.源码解读 3.1 属性解读 3.2 put方法解读 3.2.1 HashMap中的hash方法 3 ...

  4. 面试官:HashMap源码看过吧,讲一讲put方法的源码是怎样实现的???

    前言 点赞在看,养成习惯. 点赞收藏,人生辉煌. 点击关注[微信搜索公众号:编程背锅侠],第一时间获得最新文章. HashMap系列文章 第一篇 HashMap源码中的成员变量你还不懂? 来来来!!! ...

  5. 面试官系统精讲Java源码及大厂真题 - 08 HashMap 源码解析

    08 HashMap 源码解析 自信和希望是青年的特权. --大仲马 引导语 HashMap 源码很长,面试的问题也非常多,但这些面试问题,基本都是从源码中衍生出来的,所以我们只需要弄清楚其底层实现原 ...

  6. hashmap containsvalue时间复杂度_不看看HashMap源码,怎么和面试官谈薪资

    HashMap 是日常开发中,用的最多的集合类之一,也是面试中经常被问到的 Java 类之一.同时,HashMap 在实现方式上面又有十分典型的范例.不管是从哪一方面来看,学习 HashMap 都可以 ...

  7. 搞懂 Java HashMap 源码

    HashMap 源码分析 前几篇分析了 ArrayList , LinkedList ,Vector ,Stack List 集合的源码,Java 容器除了包含 List 集合外还包含着 Set 和 ...

  8. Java源码详解二:HashMap源码分析--openjdk java 11源码

    文章目录 HashMap.java介绍 1.HashMap的get和put操作平均时间复杂度和最坏时间复杂度 2.为什么链表长度超过8才转换为红黑树 3.红黑树中的节点如何排序 本系列是Java详解, ...

  9. hashmap为什么用红黑树_要看HashMap源码,先来看看它的设计思想

    HashMap 是日常开发中,用的最多的集合类之一,也是面试中经常被问到的 Java 类之一.同时,HashMap 在实现方式上面又有十分典型的范例.不管是从哪一方面来看,学习 HashMap 都可以 ...

  10. Java集合框架之三:HashMap源码解析

    Java集合框架之三:HashMap源码解析 版权声明:本文为博主原创文章,转载请注明出处,欢迎交流学习! HashMap在我们的工作中应用的非常广泛,在工作面试中也经常会被问到,对于这样一个重要的集 ...

最新文章

  1. 记一次Linux系统内存占用较高得排查
  2. mysql基础 事务的认识和使用
  3. 【C语言】结构体赋值
  4. ospf路由协议源码学习
  5. SpringMVC框架搭建( 使用Jar包搭建)
  6. JAVA数据转换常用方法
  7. java借书_用java语言实现借书系统
  8. 不断改进的FUP TC20H 台式多用途高速冷冻离心机
  9. 网络编程三剑客之sed
  10. python获取pdf页面尺寸_python-从pdf提取页面作为jpeg
  11. 常见端口对应服务及入侵方式
  12. mac svn 服务器及客户端
  13. jQuery绑定enter事件
  14. linux定时任务crond那些事!
  15. 智源发布《人工智能的认知神经基础白皮书》,一览“AI×脑科学”前沿
  16. 根号1+x的平方分之一的不定积分
  17. 华为magic book笔记本无法重装系统的麻烦
  18. 计算机鼠标左键不起作用,为什么电脑的左键点了不起作用
  19. 尹春鹏-Cocos游戏的自动化测试和崩溃分析
  20. MySQL8.0.11修改root密码

热门文章

  1. HDOJ 1071 The area (纯数学题)
  2. Java当中的运算符
  3. Disable auto select after clicking magnifier
  4. C++ 虚拟析构函数
  5. 原野小年总共拍了多少_开一家羽毛球馆大概需要投资多少钱
  6. stdthread(2)创建
  7. C++ Primer 5th笔记(chap 18 大型程序工具)捕获异常
  8. (chap3 数据链路) 数据链路概览
  9. C++ Primer 5th笔记(chap 12 动态内存)智能指针概述
  10. buu [GUET-CTF2019]BabyRSA