集合系列(八) -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;

/**负载因子,默认0.75*/
private float loadFactor;

/**记录修改的次数*/
private transient int modCount = 0;

具体各个变量含义如下:

  • **table:**表示一个由 Entry 对象组成的链表数组,Entry 是一个单向链表,哈希表的key-value键值对都是存储在 Entry 数组中的;
  • **count:**表示 Hashtable 的大小,用于记录保存的键值对的数量;
  • **threshold:**表示 Hashtable 的阈值,用于判断是否需要调整 Hashtable 的容量,threshold 等于容量 * 加载因子;
  • **loadFactor:**表示负载因子,默认为 0.75;
  • **modCount:**表示记录 Hashtable 修改的次数,用来实现快速失败抛异常处理;

接着来看看Entry这个内部类,Entry用于存储链表数据,实现了Map.Entry接口,本质是就是一个映射(键值对),源码如下:

 private static class Entry<K,V> implements Map.Entry<K,V> {
   
         /**hash值*/
        final int hash;
        /**key表示键*/
        final K key;
        /**value表示值*/
        V value;
        /**节点下一个元素*/
        Entry<K,V> next;
        ......
}

我们再接着来看看 Hashtable 初始化过程,核心源码如下:

public Hashtable() {
   
    this(11, 0.75f);
}

this 调用了自己的构造方法,核心源码如下:

public Hashtable(int initialCapacity, float loadFactor
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值