博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
HashMap和HashTable,HashMap中key和value的原理 - 跳刀的兔子 - 博客园
阅读量:4325 次
发布时间:2019-06-06

本文共 1843 字,大约阅读时间需要 6 分钟。

HashMap和HashTable,HashMap中key和value的原理 - 跳刀的兔子 - 博客园

一、HashMap和HashTable

区别:

1.HashTable是Dictionary的子类,HashMap是Map接口的一个实现类;

2.HashTable中的方法是同步的,而HashMap中方法是非同步的.也就是说,在多线程的情况下用HashMap需要额外的同步机制.

Map Collections.synchronziedMap(Map m)这个方法返回一个同步的Map,封装了底层的HashMap方法,使得多线程安全.

或者采用ConcurrentMap接口;

3.HashMap中,键和值都可以为null(null键只能有一个),HashTable不允许为null。当get()方法时返回null,即表示没有该键,也可以表示该键对应的值为null。因此判断HashMap里是否存在某个键时,不能用get()方法,应该用containsKey()方法

相同:

1.有两个参数影响性能:初始容量和加载因子。

初始容量:哈希表创建时的容量,初始容量设置太高可能会浪费空间;

加载因子:对哈希表在其容量自动增加之前可以达到多满的一个尺度(默认为.75),加载因子过高虽然减少了空间开销,但同时也增加了查询成本。

当哈希表中的条目数超出了加载因子与当前容量的乘积时,则要对该哈希表进行 rehash 操作(即重建内部数据结构)。

2.所有类的“Collection视图方法”返回的Collection的iterator方法返回的迭代器是快速失败的。

二、HashMap中key和value的原理

HashMap是基于哈希表的
Map接口的非同步实现。此实现提供所有可选的映射操作,并允许使用
null值和
null键。 HashMap 实际上是一个“链表散列”的数据结构,即
数组和链表的结合体。HashMap底层就是一个数组结构,数组中的每一项又是一个链表。当新建一个HashMap的时候,就会初始化一个数组。每个Map.Entry是一个Key-Value对,也是数组中的元素,它持有指向下一个元素的引用,这就构成了链表。 HashMap 的存取实现:

   1) 存储:

  当我们往HashMap中put元素的时候,先根据key的hashCode重新计算hash值,根据hash值得到这个元素在数组中的位置(即下标),如果数组该位置上已经存放有其他元素了,那么在这个位置上的元素将以链表的形式存放,新加入的放在链头,最先加入的放在链尾。如果数组该位置上没有元素,就直接将该元素放到此数组中的该位置上。

当系统决定存储 HashMap 中的 key-value 对时,完全没有考虑 Entry 中的 value ,仅仅只是根据 key 来计算并决定每个 Entry 的存储位置。我们完全可以把 Map 集合中的 value 当成 key 的附属,当系统决定了 key 的存储位置之后, value 随之保存在那里即可。

   hash(int h)--计算hash值的方法根据key的hashCode重新计算一次散列。此算法加入了高位计算,防止低位不变,高位变化时,造成的hash冲突。

  2) 读取:

  从HashMapget元素时,首先计算keyhashCode,找到数组中对应位置的某一元素,然后通过keyequals方法在对应位置的链表中找到需要的元素。

3)Fail-Fast 机制:

   我们知道java.util.HashMap不是线程安全的,因此如果在使用迭代器的过程中有其他线程修改了map,那么将抛出ConcurrentModificationException,这就是所谓fail-fast策略。

   这一策略在源码中的实现是通过modCount域,modCount顾名思义就是修改次数,对HashMap内容的修改都将增加这个值,那么在迭代器初始化过程中会将这个值赋给迭代器的expectedModCount。在迭代过程中,判断modCountexpectedModCount是否相等,如果不相等就表示已经有其他线程修改了Map: 注意到modCount声明为volatile,保证线程之间修改的可见性。

转载于:https://www.cnblogs.com/wang3680/p/0040532ffa032f289d2250ec255428c8.html

你可能感兴趣的文章
阶段3 2.Spring_02.程序间耦合_4 曾经代码中的问题分析
查看>>
阶段3 2.Spring_03.Spring的 IOC 和 DI_2 spring中的Ioc前期准备
查看>>
阶段3 2.Spring_03.Spring的 IOC 和 DI_4 ApplicationContext的三个实现类
查看>>
阶段3 2.Spring_02.程序间耦合_8 工厂模式解耦的升级版
查看>>
阶段3 2.Spring_03.Spring的 IOC 和 DI_6 spring中bean的细节之三种创建Bean对象的方式
查看>>
阶段3 2.Spring_03.Spring的 IOC 和 DI_3 spring基于XML的IOC环境搭建和入门
查看>>
阶段3 2.Spring_04.Spring的常用注解_3 用于创建的Component注解
查看>>
阶段3 2.Spring_04.Spring的常用注解_2 常用IOC注解按照作用分类
查看>>
阶段3 2.Spring_04.Spring的常用注解_5 自动按照类型注入
查看>>
阶段3 2.Spring_04.Spring的常用注解_7 改变作用范围以及和生命周期相关的注解
查看>>
阶段3 2.Spring_05.基于XML的IOC的案例1_3 测试基于XML的IOC案例
查看>>
阶段3 2.Spring_04.Spring的常用注解_4 由Component衍生的注解
查看>>
阶段3 2.Spring_06.Spring的新注解_2 spring的新注解-Bean
查看>>
阶段3 2.Spring_04.Spring的常用注解_6 用于注入数据的注解
查看>>
阶段3 2.Spring_06.Spring的新注解_3 AnnotationConfigApplicationContext的使用
查看>>
阶段3 2.Spring_07.银行转账案例_2 案例中添加转账方法并演示事务问题
查看>>
阶段3 2.Spring_07.银行转账案例_6 测试转账并分析案例中的问题
查看>>
阶段3 2.Spring_07.银行转账案例_7 代理的分析
查看>>
阶段3 2.Spring_07.银行转账案例_3 分析事务的问题并编写ConnectionUtils
查看>>
阶段3 2.Spring_07.银行转账案例_9 基于子类的动态代理
查看>>