相信大家对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。