相信大家对Hashtable已经有所了解了,Hashtable和HashMap,从存储结构和实现来讲基本上都是相同的。它和HashMap的最大的不同是它是线程安全的,另外它不允许key和value为null。Hashtable是个过时的集合类,不建议在新代码中使用,不需要线程安全的场合可以用HashMap替换,需要线程安全的场合可以用ConcurrentHashMap替换。但这并不是我们不去了解它的理由。最起码Hashtable和HashMap的面试题在面试中经常被问到。Hashtable是如何实现线程安全的的?Hashtable和HashMap的相同点和不同点?本文将分析Hashtable的内部结构及实现原理,帮助大家学习HashMap和Hashtable。
顶部注释
This class implements a hash table, which maps keys to values. Any non-null object can be used as a key or as a value.
这个类是哈希表的实现,key与value键值对的映射集。任何非null的对象可以用作key或者vlaue。
To successfully store and retrieve objects from a hashtable, the objects used as keys must implement the hashCode method and the equals method.
为了能在哈希表中成功地保存和取出对象,用作key的对象必须实现hashCode方法和equals方法。
An instance of Hashtable has two parameters that affect its performance: initial capacity and load factor. The capacity is the number of buckets in the hash table, and the initial capacity is simply the capacity at the time the hash table is created. Note that the hash table is open: in the case of a “hash collision”, a single bucket stores multiple entries, which must be searched sequentially. The load factor is a measure of how full the hash table is allowed to get before its capacity is automatically increased. The initial capacity and load factor parameters are merely hints to the implementation. The exact details as to when and whether the rehash method is invoked are implementation-dependent.
一个Hashtable的实例有两个影响它行为的参数:初始化容量initial capacity 和负载因子load factor。容量是哈希表中桶的数量,初始化容量是哈希表被创建时的容量。哈希表是开放的,就哈希碰撞来说,一个桶存储数个必须被顺序查找的node。负载因子是哈希表在自动扩容之前可以多满的一个度量(哈希表几乎不会在满时才会扩容,加载因子越大,在扩容前哈希表可以存放的节点就越多)。初始化容量initial capacity 和负载因子load factor仅仅对实现有细微的暗示。何时扩容,是否扩容取决于具体的实现。
Generally, the default load factor (.75) offers a good tradeoff between time and space costs. Higher values decrease the space overhead but increase the time cost to look up an entry (which is reflected in most Hashtable operations, including get and put).
一般来说,默认的加载因子0.75在哈希表和时间和空间花销上是一个很好的平衡。更高的加载因子减少了空间开销但增加了查找操作的时间开销(影响了大多的哈希表操作,包括get和put操作)。
The initial capacity controls a tradeoff between wasted space and the need for rehash operations, which are time-consuming. No rehash operations will ever occur if the initial capacity is greater than the maximum number of entries the Hashtable will contain divided by its load factor. However, setting the initial capacity too high can waste space.
初始化容量initial capacity在空间开销和扩容操作的时间开销之间控制平衡。如果initial capacity大于哈希表含有的node的数量/load factor,哈希表就不会扩容。然而,把initial capacity设置地太高就增大空间开销。
If many entries are to be made into a Hashtable, creating it with a sufficiently large capacity may allow the entries to be inserted more efficiently than letting it perform automatic rehashing as needed to grow the table.
如果提前知道hashtable将要存放许多node,创建hashtable时将initial capacity适当地设置地高些会使增加元素变得更有效率,否则容量不够大将导致频繁的扩容。
This example creates a hashtable of numbers. It uses the names of the numbers as keys:
Hashtable<String, Integer> numbers= new Hashtable<String, Integer>();
numbers.put(“one”, 1);
numbers.put(“two”, 2);
numbers.put(“three”, 3);}
To retrieve a number, use the following code:
Integer n = numbers.get(“two”);
if (n != null) {
System.out.println(“two = ” + n);
}}
这个例子演示了如何创建hashtable,存放元素,取出元素。
The iterators returned by the iterator method of the collections returned by all of this class’s “collection view methods” are fail-fast: if the Hashtable is structurally modified at any time after the iterator is created, in any way except through the iterator’s own remove method, the iterator will throw a ConcurrentModificationException. Thus, in the face of concurrent modification, the iterator fails quickly and cleanly, rather than risking arbitrary, non-deterministic behavior at an undetermined time in the future. The Enumerations returned by Hashtable’s keys and elements methods are not fail-fast.
iterator方法返回的迭代器是fail-fast的。如果在迭代器被创建后hashtable被结构型地修改了,除了迭代器自己的remove方法,迭代器会抛出一个ConcurrentModificationException异常。因此,面对在并发的修改,迭代器干脆利落的失败,而不是冒险的继续。哈希表的key和元素集合返回的Enumerations不是fail-fast的。
Note that the fail-fast behavior of an iterator cannot be guaranteed as it is, generally speaking, impossible to make any hard guarantees in the presence of unsynchronized concurrent modification. Fail-fast iterators throw ConcurrentModificationException on a best-effort basis. Therefore, it would be wrong to write a program that depended on this exception for its correctness: the fail-fast behavior of iterators should be used only to detect bugs.
迭代器的fail-fast机制并不能得到保证,它不能够保证一定出现该错误。一般来说,fail-fast会尽最大努力抛出ConcurrentModificationException异常。因此,为提高此类操作的正确性而编写一个依赖于此异常的程序是错误的做法,正确做法是:ConcurrentModificationException 应该仅用于检测 bug。
As of the Java 2 platform v1.2, this class was retrofitted to implement the Map interface, making it a member of the collection。
自从Java2开始,Hashtable继承Map接口,成为了容器中的一员。
Java Collections Framework. Unlike the new collection implementations, Hashtable is synchronized. If a thread-safe implementation is not needed, it is recommended to use HashMap in place of Hashtable. If a thread-safe highly-concurrent implementation is desired, then it is recommended to use java.util.concurrent.ConcurrentHashMap in place of Hashtable.
和新的集合实现不同,Hashtable是线程安全的。如果不需要线程安全的实现是不需要的,推荐使用HashMap代替Hashtable。如果需要线程安全的实现,推荐使用java.util.concurrent.ConcurrentHashMap代替Hashtable。
看完了上面的内容,大家应该能感觉到Hashtable确实和HashMap很相似。
下篇文章将继续讲解Hashtable。
Java 面试宝典是大明哥全力打造的 Java 精品面试题,它是一份靠谱、强大、详细、经典的 Java 后端面试宝典。它不仅仅只是一道道面试题,而是一套完整的 Java 知识体系,一套你 Java 知识点的扫盲贴。
它的内容包括:
- 大厂真题:Java 面试宝典里面的题目都是最近几年的高频的大厂面试真题。
- 原创内容:Java 面试宝典内容全部都是大明哥原创,内容全面且通俗易懂,回答部分可以直接作为面试回答内容。
- 持续更新:一次购买,永久有效。大明哥会持续更新 3+ 年,累计更新 1000+,宝典会不断迭代更新,保证最新、最全面。
- 覆盖全面:本宝典累计更新 1000+,从 Java 入门到 Java 架构的高频面试题,实现 360° 全覆盖。
- 不止面试:内容包含面试题解析、内容详解、知识扩展,它不仅仅只是一份面试题,更是一套完整的 Java 知识体系。
- 宝典详情:https://www.yuque.com/chenssy/sike-java/xvlo920axlp7sf4k
- 宝典总览:https://www.yuque.com/chenssy/sike-java/yogsehzntzgp4ly1
- 宝典进展:https://www.yuque.com/chenssy/sike-java/en9ned7loo47z5aw
目前 Java 面试宝典累计更新 400+ 道,总字数 42w+。大明哥还在持续更新中,下图是大明哥在 2024-12 月份的更新情况:
想了解详情的小伙伴,扫描下面二维码加大明哥微信【daming091】咨询
同时,大明哥也整理一套目前市面最常见的热点面试题。微信搜[大明哥聊 Java]或扫描下方二维码关注大明哥的原创公众号[大明哥聊 Java] ,回复【面试题】 即可免费领取。