【集合系列】- 深入浅出的分析 Hashtable
一、摘要
在集合系列的第一章,咱们了解到,Map 的实现类有 HashMap、LinkedHashMap、TreeMap、IdentityHashMap、WeakHashMap、Hashtable、Properties 等等。
本文主要从数据结构和算法层面,探讨 Hashtable 的实现,如果有理解不当之处,欢迎指正。
二、简介
Hashtable 一个元老级的集合类,早在 JDK 1.0 就诞生了,而 HashMap 诞生于 JDK 1.2,在实现上,HashMap 吸收了很多 Hashtable 的思想,虽然二者的底层数据结构都是 数组 + 链表 结构,具有查询、插入、删除快的特点,但是二者又有很多的不同。
打开 Hashtable 的源码可以看到,Hashtable 继承自 Dictionary,而 HashMap 继承自 AbstractMap。
public class Hashtable<K,V> extends Dictionary<K,V> implements Map<K,V>, Cloneable, java.io.Serializable { ..... }
HashMap 继承自 AbstractMap,HashMap 类的定义如下:
public class HashMap<K,V> extends AbstractMap<K,V> implements Map<K,V>, Cloneable, Serializable { ..... }
其中 Dictionary 类是一个已经被废弃的类,翻译过来的意思是这个类已经过时,新的实现应该实现 Map 接口而不是扩展此类,这一点我们可以从它代码的注释中可以看到:
/** * <strong>NOTE: This class is obsolete. New implementations should * implement the Map interface, rather than extending this class.</strong> */ public abstract class Dictionary<K,V> { ...... }
Hashtable 和 HashMap 的底层是以数组来存储,同时,在存储数据通过key
计算数组下标的时候,是以哈希算法为主,因此可能会产生哈希冲突的可能性。
通俗的说呢,就是不同的key
,在计算的时候,可能会产生相同的数组下标,这个时候,如何将两个对象放入一个数组中呢?
而解决哈希冲突的办法,有两种,一种开放地址方式(当发生 hash 冲突时,就继续以此继续寻找,直到找到没有冲突的hash值),另一种是拉链方式(将冲突的元素放入链表)。
Java Hashtable 采用的就是第二种方式,拉链法!
于是,当发生不同的key
通过一系列的哈希算法计算获取到相同的数组下标的时候,会将对象放入一个数组容器中,然后将对象以单向链表
的形式存储在同一个数组下标容器中,就像链子一样,挂在某个节点上,如下图:
与 HashMap 类似,Hashtable 也包括五个成员变量:
/**由Entry对象组成的数组*/ private transient Entry[] table; /**Hashtable中Entry对象的个数*/ private transient int count; /**Hashtable进行扩容的阈值*/ private int threshold;