每日一问:简述Java中HashMap 和 HashTable
HashMap
- Hashmap是用来存放键值对的。同时因为它基于hash表的实现,它可以实现快速的增删查改。
数据结构
jdk1.7的HashMap是用:数组+链表
jdk1.8的HashMap是用:数组+链表+红黑树
HashMap是一个集合,键值对的集合,源码中每个节点用Node<K,V>表示。
Node是一个内部类,这里的key为键,value为值,next指向下一个元素,可以看出HashMap中的元素不是一个单纯的键值对,还包含下一个元素的引用。
HashMap的数据存储
- 哈希表来存储
HashMap采用哈希表来存储数据。
哈希表(Hash table,也叫散列表),是根据关键码值(Key value)而直接进行访问的数据结构,只要输入待查找的值即key,即可查找到其对应的值。
哈希表其实就是数组的一种扩展,由数组演化而来。可以说,如果没有数组,就没有散列表。
- 哈希函数
哈希表中元素是由哈希函数确定的,将数据元素的关键字Key作为自变量,通过一定的函数关系(称为哈希函数),计算出的值,即为该元素的存储地址。 - 核心问题
建立一个哈希表之前需要解决两个主要问题:
1)构造一个合适的哈希函数,均匀性 H(key)的值均匀分布在哈希表中
2)冲突的处理
冲突:在哈希表中,不同的关键字值对应到同一个存储位置的现象。
- 哈希冲突:链式哈希表
哈希表为解决冲突,可以采用地址法和链地址法等来解决问题,Java中HashMap采用了链地址法。
链地址法,简单来说,就是数组加链表的结合。
HashMap读写效率较高,但是因为其是非同步的,即读写等操作都是没有锁保护的,所以在多线程场景下是不安全的,容易出现数据不一致的问题,在单线程场景下非常推荐使用。
HashTable
-
Hashtable 是一个散列表,它存储的内容是键值对(key-value)映射。
-
Hashtable 继承于Dictionary,实现了Map、Cloneable、java.io.Serializable接口。
-
Hashtable 的函数都是同步的,这意味着它是线程安全的。它的key、value都不可以为null。
HashTable<K,V>也是一种key-value结构,它继承自Dictionary<K,V>,实现了Map<K,V>和Cloneable以及Serializable接口。
HashTable的操作几乎和HashMap一致,主要的区别在于HashTable为了实现多线程安全,在几乎所有的方法上都加上了synchronized锁,而加锁的结果就是HashTable操作的效率十分低下。
区别
1)Hashtable是线程安全,而HashMap则非线程安全
2)HashMap可使用null作为key,Hashtable不允许null作为key
3)HashMap是对Map接口的实现,Hashtable对Map接口的实现和对Dictionary抽象类的继承
4)HashMap的初始容量是16,Hashtable初始容量是11,两者的填充因子默认都是0.75
5)HashMap与Hashtable计算hash的是方法不同
- HashMap和Hashtable的底层实现,都是数组+链表结构。