JDK HashTable详解

2017-12-20  本文已影响0人  丑男李狗蛋

先上HashTable的继承关系:


HashTable继承关系图

为了方便比较同时放出HashMap的继承关系:

HashMap的继承关系

可以看出HahMap和HashTable都实现了Map接口,只是父类不一样

HashTable的计算哈希是直接取得key本身的哈希:

  int hash = key.hashCode();

这里可以看出,hashtable是不支持null值的,并且在put的时候取哈希之前已经判定了value为空判定,虽然key没有判定,但是在取hash的时候由于key是null所以一定会抛出java.lang.NullPointerException

if (value == null) {
throw new NullPointerException();
}

HashTable每次扩容是原有容量的2倍+1( (oldCapacity << 1) + 1),通过rehash()来实现扩容的

HashTable是的每个哈希桶的元素都是链表,相对来说如果每个哈希桶元素比较多的话,处理效率是比较低的,接下来划重点,这实质就是哈希表的实质,一张课表


课表

我们首先取得今天的日期,比如星期三,然后一节一节比较,寻找文体活动这门课,毕竟大家都不喜欢上课,过程和HashTable完全一致

哈希桶就相当于一个表格,首先从X轴取得哈希桶位置再在Y轴比较获取元素真实位置。

HashTable的计算索引的方式是:

 (hash & 0x7FFFFFFF) % tab.length
这里为什么要与0x7FFFFFFF是因为Hash的值会是负数,0x7FFFFFFF是Integer.MAX_VALUE,使用Math.abs()也可以达到想用的效果,但是为什么不用它呢

主要原因如下图所示:


0x7FFFFFFF 和Math.abs()的区别
计算结果

可以看到当hash为Integer的最小值的时候,会导致Math.abs取得负数值,这样计算出来的index下标也是负值,而java的数组下标不能为负数,否则会导致程序异常

最终将node追加到哈希哈希桶某个哈西位置的尾部,就完成了整个存储过程

需要注意的是:HashTable是线程安全的,HashTable所有public方法都添加了synchronized关键字,保证线程同步不会出错。但是同时因为线程安全机制导致HashTable的存取效率不如HashMap

比较上一篇文章 JDK HashMap详解 而言,HashTable虽然都实现了Map接口,但各自有着不同的应用场景,总结起来有如下不同点:

If a thread-safe implementation is not needed, it is recommended to use
{@link HashMap} in place of {@code Hashtable}. If a thread-safe
highly-concurrent implementation is desired, then it is recommended
to use {@link java.util.concurrent.ConcurrentHashMap} in place of
{@code Hashtable}.
大致含义为:如果你不需要线程同步,建议使用HashMap来代替HashTable,如果你的你是需要线程同步的话使用ConcurrentHashMap来替代Hashtable

上一篇 下一篇

猜你喜欢

热点阅读