集合(一)- HashMap和HashSet和HashTable的区别

参考文章:

  1. hashmap的hash算法:https://www.cnblogs.com/eycuii/p/12015283.html
  2. hashmap和hashtable的区别:https://www.zhihu.com/question/20581065/answer/334969310
  3. hashmap源码:https://zhuanlan.zhihu.com/p/79219960
  4. 负载因子:https://zhuanlan.zhihu.com/p/103449454

HashMap简介

  1. 特点
  • 初始大小为16,每次扩容以2的指数增长

  • HashMap是基于哈希表来实现的,每一个元素是一个key-value对,其内部通过单链表解决冲突问题,容量不足时,同样会自动增长。

  • HashMap是非线程安全的,只能用于单线程环境下,多线程环境下可以采用concurrent并发包下的concurrenHashMap。

  • HashMap实现了Serializable接口,因此它支持序列化,实现了Cloneable接口,能被克隆。

  • 存储过程原理:

内部维护了一个存储数据的Entry数组,HashMap采用链表解决冲突,每一个Entry本质上是一个单向链表,当准备添加一个key-value对时,首先通过hash(key)方法计算hash值,任何通过indexfor(hash,length)求该key-value的存储位置,计算方法时先用hash&0x7FFFFFFF后,再对length取模,这就保证每一个key-value对都能存入hashmap中。

  • 扩容后hash值
第三部分同样也很复杂,就是把旧数据复制到新数组里面。这里面需要注意的有下面几种情况:

A:扩容后,若hash值新增参与运算的位=0,那么元素在扩容后的位置=原始位置

B:扩容后,若hash值新增参与运算的位=1,那么元素在扩容后的位置=原始位置+扩容后的旧位置。

hash值新增参与运算的位是什么呢?我们把hash值转变成二进制数字,新增参与运算的位就是倒数第五位。

这里面有一个非常好的设计理念,扩容后长度为原hash表的2倍,于是把hash表分为两半,分为低位和高位,如果能把原链表的键值对, 一半放在低位,一半放在高位,而且是通过e.hash & oldCap == 0来判断,这个判断有什么优点呢?

举个例子:n = 16,二进制为10000,第5位为1,e.hash & oldCap 是否等于0就取决于e.hash第5 位是0还是1,这就相当于有50%的概率放在新hash表低位,50%的概率放在新hash表高位。

  • HashMap中key和value都允许为null,key为null的键值对永远都放在以table[0]为头结点的链表中。

存储结构图解
在这里插入图片描述

HashTable简介

-Hashtable同样是基于哈希表实现的,同样每个元素是一个key-value对,其内部也是通过单链表解决冲突问题,容量不足(超过了阀值)时,同样会自动增长。

  • Hashtable也是JDK1.0引入的类,是线程安全的,能用于多线程环境中。
    
  • Hashtable同样实现了Serializable接口,它支持序列化,实现了Cloneable接口,能被克隆。

HashTable和HashMap区别

  1. 继承的父类不同

Hashtable继承自Dictionary类,而HashMap继承自AbstractMap类。但二者都实现了Map,Cloneable(可复制)、Serializable(可序列化)这三个接口。

  1. 线程安全性不同
    javadoc中关于hashmap的一段描述如下:此实现不是同步的。如果多个线程同时访问一个哈希映射,而其中至少一个线程从结构上修改了该映射,则它必须保持外部同步。

  2. 是否提供contains方法

  • hashmap把hashtable的contains方法去掉了,改成了cotainsValue和containskey,因为contains容易让人误解。
  • hashtable则保留了contains,containsValue和containsKey三个方法,其中contains和containsValue功能相同。
  1. key和value是否允许null值
    其中key和values都是对象,并且不能包含重复可以。
  • hashmap可以有一个null的键值对(null,null),只能一个,所以,当get()方法返回null值时,可能是 HashMap中没有该键,也可能使该键所对应的值为null。因此,在HashMap中不能由get()方法来判断HashMap中是否存在某个键, 而应该用containsKey()方法来判断。
  • ==hashtable不允许出现null值,==但是如果在Hashtable中有类似put(null,null)的操作,编译同样可以通过,因为key和value都是Object类型,但运行时会抛出NullPointerException异常,这是JDK的规范规定的。
  1. 内部遍历方式不同
    Hashtable、HashMap都使用了 Iterator。而由于历史原因,Hashtable还使用了Enumeration的方式 。

  2. hash值不同
    在这里插入图片描述
    Hashtable直接使用对象的hashCode。hashCode是JDK根据对象的地址或者字符串或者数字算出来的int类型的数值。然后再使用除留余数发来获得最终的位置。
    Hashtable在计算元素的位置时需要进行一次除法运算,而除法运算是比较耗时的。HashMap为了提高计算效率,将哈希表的大小固定为了2的幂,这样在取模预算时,不需要做除法,只需要做位运算。位运算比除法的效率要高很多。
    在这里插入图片描述
    HashMap为了提高计算效率,将哈希表的大小固定为了2的幂,这样在取模预算时,不需要做除法,只需要做位运算。位运算比除法的效率要高很多。

    HashMap的效率虽然提高了,但是hash冲突却也增加了。因为它得出的hash值的低位相同的概率比较高,而计算位运算为了解决这个问题,HashMap重新根据hashcode计算hash值后,又对hash值做了一些运算来打散数据。使得取得的位置更加分散,从而减少了hash冲突。当然了,为了高效,HashMap只做了一些简单的位处理。从而不至于把使用2 的幂次方带来的效率提升给抵消掉。

  3. 初始容量和大小不同
    Hashtable默认的初始大小为11,之后每次扩充,容量变为原来的2n+1。HashMap默认的初始化大小为16。之后每次扩充,容量变为原来的2倍。创建时,如果给定了容量初始值,那么Hashtable会直接使用你给定的大小,而HashMap会将其扩充为2的幂次方大小。也就是说Hashtable会尽量使用素数、奇数。而HashMap则总是使用2的幂作为哈希表的大小。

hashmap和hashset的区别

HashMap      HashSet

1.HashMap实现了Map接口     HashSet实现了Set接口

2.HashMap储存键值对      HashSet仅仅存储对象

3.使用put()方法将元素      使用add()方法将元素放入set中放入map中

4.HashMap中使用键对象来计算     HashSet使用成员对象来计算hashcode值,对于hashcode值

5.HashMap比较快,因为它使用     HashSet较HashMap来说比较慢

1、继承不同。public class Hashtable extends Dictionary implements Map

public class HashMap extends AbstractMap implements Map

2、Hashtable 中的方法是同步的,而HashMap中的方法在缺省情况下是非同步的。在多线程并发的环境下,可以直接使用Hashtable,但是要使用HashMap的话就要自己增加同步处理了。

3、Hashtable中,key和value都不允许出现null值。

在HashMap中,null可以作为键,这样的键只有一个;可以有一个或多个键所对应的值为null。当get()方法返回null值时,即可以表示 HashMap中没有该键,也可以表示该键所对应的值为null。因此,在HashMap中不能由get()方法来判断HashMap中是否存在某个键, 而应该用containsKey()方法来判断。

4、两个遍历方式的内部实现上不同。

Hashtable、HashMap都使用了 Iterator。而由于历史原因,Hashtable还使用了Enumeration的方式 。

5、哈希值的使用不同,HashTable直接使用对象的hashCode。而HashMap重新计算hash值。

6、Hashtable和HashMap它们两个内部实现方式的数组的初始大小和扩容的方式。HashTable中hash数组默认大小是11,增加的方式是 old*2+1。HashMap中hash数组的默认大小是16,而且一定是2的指数

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值