关于Map接口

1.HashMap 概述

概述

基于哈希表的 Map 接口的实现。此实现提供所有可选的映射操作,并允许使用 null 值(多个)和 null 键(一个)。(除了非同步和允许使用 null 之外,HashMap 类与 Hashtable 大致相同。)具有很快的访问速度,但遍历顺序却是不确定的

HashMap线程安全吗?

HashMap非线程安全,即任一时刻可以有多个线程同时写HashMap,可能会导致数据的不一致。如果需要满足线程安全,可以用 Collections的synchronizedMap方法使HashMap具有线程安全的能力,或者使用ConcurrentHashMap

2.HashMap 的实现原理?

HashMap 基于 Hash 算法实现的

  • 当我们往HashMap中put元素时,利用key的hashCode重新hash计算出当前对象的元素在数组中的下标
  • 存储时,如果出现hash值相同的key,此时有两种情况。(1)如果key相同,则覆盖原始值;(2)如果key不同(出现冲突),则将当前的key-value放入链表中
  • 获取时,直接找到hash值对应的下标,在进一步判断key是否相同,从而找到对应值

3.HashMap的数据存储结构

从结构实现来讲,HashMap是:数组+链表+红黑树(JDK1.8增加了红黑树部分)实现的

  • HashMap采用Entry数组来存储key-value对,每一个键值对组成了一个Entry实体,Entry类实际上是一个单向的链表结构,它具有Next指针,可以连接下一个Entry实体,以此来解决Hash冲突的问题
  • Jdk 1.8中对HashMap的实现做了优化,当链表中的节点数据超过八个之后,该链表会转为红黑树来提高查询效率,从原来的O(n)到O(logn)

在这里插入图片描述

为什么引入红黑树

因为即使负载因子和Hash算法设计的再合理,也会出现拉链过长的情况,一旦出现拉链过长,则会严重影响HashMap的性能。所以引入红黑树是为了增加HashMap的性能,提高HashMap对插入、删除、查找的效率。

4.数据底层具体存储的是什么?这样的存储方式有什么优点呢?

数据底层存储对象

HashMap类中有一个非常重要的字段,就是 Node[] table,即哈希桶数组,明显它是一个Node的数组。Node是HashMap的一个内部类,实现了Map.Entry接口,本质是就是一个映射(键值对)。上图中的每个黑色圆点就是一个Node对象

优点

HashMap就是使用哈希表来存储的。哈希表为解决冲突,可以采用开放地址法和链地址法等来解决问题,Java中HashMap采用了链地址法。链地址法,就是数组加链表的结合。在每个数组元素上都一个链表结构,当数据被Hash后,得到数组下标,把数据放在对应下标元素的链表上。例如程序执行下面代码:

map.put("1","A");

系统将调用”1”这个key的hashCode()方法得到其hashCode 值(该方法适用于每个Java对象),然后再通过Hash算法的后两步运算(高位运算和取模运算)来定位该键值对的存储位置,有时两个key会定位到相同的位置,则表示发生了Hash碰撞。

5.HashMap扩容机制

在理解Hash和扩容流程之前,我们得先了解下HashMap的几个字段。

int threshold; // 所能容纳的key-value对极限 
int modCount;  //记录HashMap内部结构发生变化的次数
int size;  	   //HashMap中键值对数量
static final float DEFAULT_LOAD_FACTOR = 0.75f //负载因子为0.75
static final int DEFAULT_INITIAL_CAPACITY = 1 << 4 //Node[] table的初始化长度为16

扩容机制

扩容就是当hashmap中的键值对达到阈值(负载因子*初始长度)时将原数组扩大为原来的两倍,即容量达到最大容量的75%时(这个百分比由负载因子决定)。

6.put方法的流程

在这里插入图片描述

7.HashMap为什么要保证hashmap的容量为2的幂次方?

  • 为了减小哈希冲突。因为当存在哈希冲突的时候,存储entry的时,会出现一个位置上存在多个entry,造成读写速度的降低;
  • 使用2的幂次方的容量,存储的时候,会根据key的哈希值跟hashmap的(容量-1)进行位运算,而当(容量-1)的二进制数全为1的时候,存储位置的计算结果是哈希冲突最小的。

8.为什么HashMap中String、Integer这样的包装类适合作为Key?

  • String、Integer等包装类的特性能够保证Hash值的不可更改性和计算准确性,能够有效的减少Hash碰撞的几率
  • 都是final类型,即不可变性,保证key的不可更改性,不会存在获取hash值不同的情况
  • 内部已重写了equals()、hashCode()等方法,遵守了HashMap内部的规范,不容易出现Hash值计算错误的情况

9.如果Object作为HashMap的Key,应该怎么办呢?

应该重写hashCode()和equals()方法

  • 重写hashCode()方法:是因为需要计算存储数据的存储位置
  • 重写equals()方法:目的是为了保证key在哈希表中的唯一性

10.线程安全的Map都有哪些?性能最好的是哪个?

  • 线程安全的有HashTable、ConcurrentHashMap、SynchronizedMap
  • 性能最好的是ConcurrentHashMap

11.怎么按添加顺序存储元素?怎么按A-Z自然顺序存储元素?怎么自定义排序?

  • 按添加顺序:LinkedHashMap
  • 按自然顺序:TreeMap
  • 自定义排序:TreeMap(Comparetor c)

12.HashMap 和 ConcurrentHashMap 的区别

  • ConcurrentHashMap对整个桶数组进行了分割分段(Segment),然后在每一个分段上都用lock锁进行保护,相对于HashTable的synchronized锁的粒度更精细了一些,并发性能更好
  • 而HashMap没有锁机制,不是线程安全的。(JDK1.8之后ConcurrentHashMap启用了一种全新的方式实现,利用CAS算法。)
  • HashMap的键值对允许有null,但是ConCurrentHashMap都不允许

关于CAS

  • CAS是compare and swap的缩写,即我们所说的比较交换。cas是一种基于锁的操作,而且是乐观锁。在java中锁分为乐观锁和悲观锁。悲观锁是将资源锁住,等一个之前获得锁的线程释放锁之后,下一个线程才可以访问。而乐观锁采取了一种宽泛的态度,通过某种方式不加锁来处理资源,比如通过给记录加version来获取数据,性能较悲观锁有很大的提高。

  • CAS 操作包含三个操作数 —— 内存位置(V)、预期原值(A)和新值(B)。如果内存地址里面的值和A的值是一样的,那么就将内存里面的值更新成B。CAS是通过无限循环来获取数据的,若果在第一轮循环中,a线程获取地址里面的值被b线程修改了,那么a线程需要自旋,到下次循环才有可能机会执行。

13.ConcurrentHashMap总结

  • 数据结构
    取消了Segment分段锁的数据结构,取而代之的是数组+链表+红黑树的结构
  • 保证线程安全机制
    JDK1.7采用segment的分段锁机制实现线程安全,其中segment继承自ReentrantLock。JDK1.8采用CAS+Synchronized保证线程安全
  • 锁的粒度
    原来是对需要进行数据操作的Segment加锁,现调整为对每个数组元素加锁(Node)
  • 链表转化为红黑树
    定位结点的hash算法简化会带来弊端,Hash冲突加剧,因此在链表节点数量大于8时,会将链表转化为红黑树进行存储。
  • 查询时间复杂度
    从原来的遍历链表O(n),变成遍历红黑树O(logN)。

14.HashMap小结

  • 扩容是一个特别耗性能的操作,所以当程序员在使用HashMap的时候,估算map的大小,初始化的时候给一个大致的数值,避免map进行频繁的扩容
  • 负载因子是可以修改的,也可以大于1,但是建议不要轻易修改,除非情况非常特殊
  • HashMap是线程不安全的,不要在并发的环境中同时操作HashMap,建议使用ConcurrentHashMap
  • JDK1.8引入红黑树大程度优化了HashMap的性能
  • HashMap的性能提升仅仅是JDK1.8的冰山一角
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值