HashTable源码观摩

104 阅读4分钟
  • 持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第27天,点击查看活动详情

前言

观摩源码三部曲

  1. 第一步:看类图
  2. 第二步:看结构
  3. 第三步:看源码

1. 类图

HashTable的类图

image.png

HashTable继承了抽象类Dictionary,实现了Map、Cloneable、Serializable

  • Dictionary

Dictionary的作用跟Map类似,给出键和值,你就可以将值存储在Dictionary对象中。一旦该值被存储,就可以通过它的键来获取它。所以和Map一样, Dictionary 也可以作为一个键/值对列表。

在源码中Dictionary的注释标注了此类是一个过时的类,不再建议使用,如下:

image.png

  • Map

      Map就不用说了,定义K,V结构的接口
    
  • Cloneable

      Cloneable就是为了实现深克隆实现的,默认的clone都是浅拷贝,对象就复制的对象引用,基础数据类型就赋值,浅拷贝情况下对象的实际内容发生改变,clone的对象值也会改变,因为复制的对象指用。
    
  • Serializable

      Serializable序列化使用的,应该无需解释
    

2. 看结构

HashTable的结构图

image.png

除了想上重写的方法和实现方法,只有构造方法跟contains是对外开放的public级方法。

这可就好奇contains方法内容做了什么,像在源码内实现类对外直接开放的public方法还是甚少的,都是父类或者接口编写好对外开放的方法,子类或者实现类编写逻辑,一般不会直接提供public方法,但是可能会提供protected方法来让同级别类调用做协同操作

看一下那些外部类引用到了contains方法

image.png

在java 1.8内除了Hashtable自己的方法调用了contains方法外还有两个类直接使用到了这两个方法

  • AccessibleBundle
  • StyleSheet

3. 源码

3.1 构造函数

Hashtable有四个构造函数,Hashtable(int,float)这个构造函数是四个构造函数的核心,所以先看这个

3.1.1 有参构造函数 Hashtable(int,float)

源码

image.png

在这个构造函数中传入的参数int跟float值是为了定义HashTable的初始大小跟下一次扩容的大小


    1. 判断参数int值是否小于0,小于直接抛出异常
    1. 判断参数float小于等于0时或者为非数时也抛出异常,NAN为非数
    1. 判断参数int是否为0,如果为0赋值为1
    1. 定义Hashtable的扩容因子,这个扩容因子是计算下一次的扩容阈值使用的
    1. 初始化Entry结构并初始化长度为传入参数int值,最小为1
    1. 计算下一次要扩容的阈值并记录到threshold参数中

经过这6步我们的初始化就完成了,其他的构造函数也都是使用的这个构造函数进行的初始化,无非就是传参的不同

3.1.2 无参构造函数 Hashtable()

此构造函数直接使用的有参构造函数 Hashtable(int,float),默认值设置的110.75,也就是使用此构造函数进行初始化的默认因子是0.75、默认长度是11,,下一次的扩容阈值就是:11*0.75

image.png

3.1.3 有参构造函数 Hashtable(int)

此构造函数直接使用的有参构造函数 Hashtable(int,float),默认值设置的0.75,也就是使用此构造函数进行初始化的默认因子是0.75,下一次的扩容阈值就是:(int值)*0.75

image.png

3.1.4 有参构造函数 Hashtable(Map< ? extends K, ? extends V>)

此构造函数入参为Map接口,也就是实现Map接口的类都可以通过此函数获得一个Hashtable类,它也是直接使用的有参构造函数 Hashtable(int,float),只不过多了一步赋值的操作跟计算初始化大小的操作

image.png

3.2 局部方法

3.2.1 contains(Object)

这个局部方法是Hashtable唯一public级别的方法,它的作用就是对传入参数value判断在Hashtable内是否存在,这个方法的操作比containsKey方法更加消耗资源,并且如果传入参数为空也会报错

image.png

3.2.2 rehash()

Hashtable扩容的方法,当哈希表中的键数超过此哈希表的容量和负载因子时,将自动调用此方法。

image.png