HashMap和HashTable简介和区别
一、HashMap简介
HashMap是基于哈希表实现的,每一个元素是一个key-value对,其内部通过单链表解决冲突问题,容量不足(超过了阀值)时,同样会自动增长。
HashMap是非线程安全的,只是用于单线程环境下,多线程环境下可以采用concurrent并发包下的concurrentHashMap。
HashMap 实现了Serializable接口,因此它支持序列化,实现了Cloneable接口,能被克隆。
HashMap存数据的过程是:
HashMap内部维护了一个存储数据的Entry数组,HashMap采用链表解决冲突,每一个Entry本质上是一个单向链表。当准备添加一个key-value对时,首先通过hash(key)方法计算hash值,然后通过indexFor(hash,length)求该key-value对的存储位置,计算方法是先用hash&0x7FFFFFFF后,再对length取模,这就保证每一个key-value对都能存入HashMap中,当计算出的位置相同时,由于存入位置是一个链表,则把这个key-value对插入链表头。
HashMap中key和value都允许为null。key为null的键值对永远都放在以table[0]为头结点的链表中。
了解了数据的存储,那么数据的读取也就很容易就明白了。
HashMap的存储结构,如下图所示:

图中,紫色部分即代表哈希表,也称为哈希数组,数组的每个元素都是一个单链表的头节点,链表是用来解决冲突的,如果不同的key映射到了数组的同一位置处,就将其放入单链表中。
HashMap内存储数据的Entry数组默认是16,如果没有对Entry扩容机制的话,当存储的数据一多,Entry内部的链表会很长,这就失去了HashMap的存储意义了。所以HasnMap内部有自己的扩容机制。HashMap内部有:
变量size,它记录HashMap的底层数组中已用槽的数量;
变量threshold,它是HashMap的阈值,用于判断是否需要调整HashMap的容量(threshold = 容量*加载因子)
变量DEFAULT_LOAD_FACTOR = 0.75f,默认加载因子为0.75
HashMap扩容的条件是:当size大于threshold时,对HashMap进行扩容
扩容是是新建了一个HashMap的底层数组,而后调用transfer方法,将就HashMap的全部元素添加到新的HashMap中(要重新计算元素在新的数组中的索引位置)。 很明显,扩容是一个相当耗时的操作,因为它需要重新计算这些元素在新的数组中的位置并进行复制处理。因此,我们在用HashMap的时,最好能提前预估下HashMap中元素的个数,这样有助于提高HashMap的性能。
HashMap共有四个构造方法。构造方法中提到了两个很重要的参数:初始容量和加载因子。这两个参数是影响HashMap性能的重要参数,其中容量表示哈希表中槽的数量(即哈希数组的长度),初始容量是创建哈希表时的容量(从构造函数中可以看出,如果不指明,则默认为16),加载因子是哈希表在其容量自动增加之前可以达到多满的一种尺度,当哈希表中的条目数超出了加载因子与当前容量的乘积时,则要对该哈希表进行 resize 操作(即扩容)。
下面说下加载因子,如果加载因子越大,对空间的利用更充分,但是查找效率会降低(链表长度会越来越长);如果加载因子太小,那么表中的数据将过于稀疏(很多空间还没用,就开始扩容了),对空间造成严重浪费。如果我们在构造方法中不指定,则系统默认加载因子为0.75,这是一个比较理想的值,一般情况下我们是无需修改的。
另外,无论我们指定的容量为多少,构造方法都会将实际容量设为不小于指定容量的2的次方的一个数,且最大值不能超过2的30次方。
二、Hashtable简介
Hashtable同样是基于哈希表实现的,同样每个元素是一个key-value对,其内部也是通过单链表解决冲突问题,容量不足(超过了阀值)时,同样会自动增长。
Hashtable也是JDK1.0引入的类,是线程安全的,能用于多线程环境中。
Hashtable同样实现了Serializable接口,它支持序列化,实现了Cloneable接口,能被克隆。
三、HashMap和Hashtable的区别
1、两者最主要的区别在于Hashtable是线程安全,而HashMap则非线程安全。Hashtable的实现方法里面都添加了synchronized关键字来确保线程同步,因此相对而言HashMap性能会高一些,我们平时使用时若无特殊需求建议使用HashMap,在多线程环境下若使用HashMap需要使用Collections.synchronizedMap()方法来获取一个线程安全的集合(Collections.synchronizedMap()实现原理是Collections定义了一个SynchronizedMap的内部类,这个类实现了Map接口,在调用方法时使用synchronized来保证线程同步,当然了实际上操作的还是我们传入的HashMap实例,简单的说就是Collections.synchronizedMap()方法帮我们在操作HashMap时自动添加了synchronized来实现线程同步,类似的其它Collections.synchronizedXX方法也是类似原理。
2、HashMap可以使用null作为key,不过建议还是尽量避免这样使用。HashMap以null作为key时,总是存储在table数组的第一个节点上。而Hashtable则不允许null作为key。
3、HashMap继承了AbstractMap,HashTable继承Dictionary抽象类,两者均实现Map接口。
4、HashMap的初始容量为16,Hashtable初始容量为11,两者的填充因子默认都是0.75。
5、HashMap扩容时是当前容量翻倍即:capacity*2,Hashtable扩容时是容量翻倍+1即:capacity*2+1。
6、HashMap和Hashtable的底层实现都是数组+链表结构实现。
7、两者计算hash的方法不同: Hashtable计算hash是直接使用key的hashcode对table数组的长度直接进行取模:
int hash = key.hashCode();
int index = (hash & 0x7FFFFFFF) % tab.length;
HashMap计算hash对key的hashcode进行了二次hash,以获得更好的散列值,然后对table数组长度取摸:
static int hash(int h) {
h ^= (h >>> 20) ^ (h >>> 12);
return h ^ (h >>> 7) ^ (h >>> 4);
}
static int indexFor(int h, int length) {
return h & (length-1);
}
参考上海尚学堂Java文章:http://www.shsxt.com/it/java/993.html,获取更多内容或支持,请点击 上海Java培训
HashMap和HashTable简介和区别的更多相关文章
- HashMap 和 Hashtable 有什么区别?(未完成)
HashMap 和 Hashtable 有什么区别?(未完成)
- ArrayList,Vector,HashMap,HashSet,HashTable之间的区别与联系
在编写java程序中,我们最常用的除了八种基本数据类型,String对象外还有一个集合类,在我们的的程序中到处充斥着集合类的身影!java中集合大家族的成员实在是太丰富了,有常用的ArrayList. ...
- HashMap与HashTable联系与区别
HashMap与HashTable 1.hashMap去掉了HashTable 的contains方法,但是加上了containsValue()和containsKey()方法. 2.hashTabl ...
- HashMap和HashTable本质性的区别
一,HashMap 1.HashMap是键值对key-value形式双列集合.它的底层存储原理是哈希表. 2.对应HashMap采用哈希表存储键值对元素的方式. HashMap.put(key,val ...
- LinkedList,ArrayList,Vector,HashMap,HashSet,HashTable之间的区别与联系
在编写java程序中,我们最常用的除了八种基本数据类型,String对象外还有一个集合类,在我们的的程序中到处充斥着集合类的身影!java中集合大家族的成员实在是太丰富了,有常用的ArrayList. ...
- HashMap、HashTable、ConcurrentHashMap区别
HashMap与HashTable区别 HashMap与ConcurrentHashMap区别 1.HashMap与HashTable的区别 HashMap线程不安全,HashTable线程安全 Ha ...
- Java的HashMap和Hashtable有什么区别HashSet和HashMap有什么区别?使用这些结构保存的数需要重载的方法是哪些?
HashMap与Hashtable实现原理相同,功能相同,底层都是哈希表结构,查询速度快,在很多情况下可以互用 两者的主要区别如下 1.Hashtable是早期JDK提供的接口,HashMap是新版J ...
- HashMap 和 Hashtable两者的区别以和解释
HashMap 和 Hashtable 是 Java 开发程序员必须要掌握的,也是在各种 Java 面试场合中必须会问到的. 但你对这两者的区别了解有多少呢? 现在,栈长我给大家总结一下,或许有你不明 ...
- hashMap,hashTable,concurrentHashMap区别
HashTable 底层数组+链表实现,无论key还是value都不能为null,线程安全,实现线程安全的方式是在修改数据时锁住整个HashTable,效率低,ConcurrentHashMap做了相 ...
随机推荐
- call(),apply()和bind()的区别
javascript中的每一个Function对象都有一个apply()和一个call()方法,它们的语法分别是: /*apply()方法*/ function.apply(thisObj[, arg ...
- js拼音排序
js拼音排序 var arr =['a','c','b','b']; arr.sort( function compareFunction(p1, p2) { return p1.localeComp ...
- python批量重命名【截取文件名前六个字符 】
#!/usr/bin/python # -*- coding: UTF-8 -*- import os, sys # 打开文件 path = "/home/landv/Desktop/l/& ...
- docker 安装使用 mssql2017
1.拉取镜像 官方文档参考 : https://docs.microsoft.com/zh-cn/sql/linux/quickstart-install-connect-docker?view=sq ...
- [转] JS中的call()方法和apply()方法用法总结
//例1 <script> window.color = 'red'; document.color = 'yellow'; var s1 = {color: 'blue' }; func ...
- MySql恢复密码的过程
密码是一个非常重要的东西,所以往往设置的很复杂,也往往一不小心.......就忘了 : ( 很多童鞋在Linux下看到一堆命令行往往都是一脸懵逼,不知从何下手,这里记录了下基本的恢复操作以备不时之需 ...
- 实时同步到Hbase的优化-1
最近没有管测试环境的 def putMapData(tableName: String , columnFamily:String, key:String , mapData:Map[String , ...
- 连接数据库出现java.sql.SQLException: Unknown system variable 'tx_isolation'
问题分析 :mysql-connector-java的版本太低,数据库的版本太高 因此将mysql-connector-java升级到最新版本就解 .或者降低MySQL的版本.我之前用的是8.0版本 ...
- css处理事件透过、点击事件透过
// 执行一些动作... $("#myModal2").css("pointer-events","none"); // 执行一些动作... ...
- 使用pl/sql developer登陆不了oracle
1,Oracle ORA12514 监听程序当前无法识别连接描述符中请求的服务 这里最主要的原因在于:(参考:https://www.cnblogs.com/shangshan/p/6359880.h ...