一 概述
深入理解Java集合中的源代码,可以帮助我们更好地了解大佬的意图,规避不必要的bug。
Hashtable 可以说已经具有一定的历史了,现在也很少使用到 Hashtable 了,更多的是使 用 HashMap 或 ConcurrentHashMap。HashTable 是一个线程安全的哈希表,它通过使用 synchronized 关键字来对方法进行加锁,从而保证了线程安全。但这也导致了在单线程 环境中效率低下等问题。Hashtable 与 HashMap 不同,它不允许插入 null 值和 null 键。
二 属性
Hashtable 并没有像 HashMap 那样定义了很多的常量,而是直接写死在了方法里(看下 去就知道了),所以它的属性相比 HashMap 来说,可以获取的信息还是比较少的
1 | //哈希表 |
三 方法
1 构造方法
1 | public Hashtable(int initialCapacity, float loadFactor) { |
二话不说,上来先丢了三个构造函数。从构造函数中,我们可以获取到这些信息: Hashtable默认的初始化容量为11(与HashMap不同),负载因子默认为0.75(与HashMap 相同)。而正因为默认初始化容量的不同,同时也没有对容量做调整的策略,所以可以 先推断出,Hashtable 使用的哈希函数跟 HashMap 是不一样的(事实也确实如此)。
2 get方法
1 | public synchronized V get(Object key) { |
跟 HashMap 相比,Hashtable 的 get 方法非常简单。我们首先可以看见 get 方法使用了 synchronized 来修饰,所以它能保证线程安全。并且它是通过链表的方式来处理冲突的。 另外,我们还可以看见 HashTable 并没有像 HashMap 那样封装一个哈希函数,而是直接 把哈希函数写在了方法中。而哈希函数也是比较简单的,它仅对哈希表的长度进行了取模。
3 put方法
1 | public synchronized V put(K key, V value) { |
put 方法一开始就表明了不能有 null 值,否则就会向你抛出一个空指针异常。Hashtable 的 put 方法也是使用 synchronized 来修饰。你可以发现,在 Hashtable 中,几乎所有的方 法都使用了 synchronized 来保证线程安全。
4 remove方法
1 | public synchronized V remove(Object key) { |
rehash方法
1 | protected void rehash() { |
Hashtable 的 rehash 方法相当于 HashMap 的 resize 方法。跟 HashMap 那种巧妙的 rehash 方式相比,Hashtable 的 rehash 过程需要对每个键值对都重新计算哈希值,而比起异或 和与操作,取模是一个非常耗时的操作,所以这也是导致效率较低的原因之一。