2.Hashtable
Hashtable,顾名思义,哈希表,本来是已经被淘汰的内容,但在某一版本的Java将其实现了Map接口,因此也成为常用的集合类,但是hashtable由于和hashmap十分相似,因此据说也成为“面试经典题”。由于两者的区别网上实在太多太多,我就不自己在摸索了直接拷贝过来用于借鉴:
- HashMap可以接受为null的键值(key)和值(value),而Hashtable则不行。
- HashMap是非synchronized,而Hashtable是synchronized,这意味着Hashtable是线程安全的,多个线程可以共享一个Hashtable;而如果没有正确的同步的话,多个线程是不能共享HashMap的。Java 提供了ConcurrentHashMap,它解决了HashMap的线程不安全的问题和Hashtable效率低的问题。
- 由于Hashtable是线程安全的也是synchronized,所以在单线程环境下它比HashMap要慢。如果你不需要同步,只需要单一线程,那么使用HashMap性能要好过Hashtable。
- 还有一点,算不上区别吧,HashMap是继承实现了Map接口的虚类AbstractMap,而Hashtable继承Dictionary类,并且实现Map接口。
至于前三点可以说是最多被提及的,当然HashMap可以通过下面的语句进行同步:
Map m = Collections.synchronizeMap(hashMap);
然后我们来深入讨论一下其他的的几个区别
- 是HashMap的迭代器(Iterator)是fail-fast迭代器,而Hashtable的enumerator迭代器不仅仅是fail-fast的,还使用了Enumeration的方式。所以当有其它线程改变了HashMap的结构(增加或者移除元素),将会抛出ConcurrentModificationException,但迭代器本身的remove()方法移除元素则不会抛出ConcurrentModificationException异常。但这并不是一个一定发生的行为,要看JVM。这条同样也是Enumeration和Iterator的区别。
前面咱们已经讨论过HashMap的一些遍历方式,可以确定的是HashMap的遍历方式Hashtable都有,但是Hashtable在此基础上还有Enumeration的方式,我们直接以实例来展示:
public static void main(String [] args) { Hashtable ht = new Hashtable<String, Integer>(); for(int i=100;i<105;i++) { ht.put(String.valueOf(i)+"th",i); } System.out.println(ht); Enumeration enu = ht.keys(); while(enu.hasMoreElements()) { System.out.println(enu.nextElement()); } }
结果如下:
{102th=102, 104th=104, 101th=101, 103th=103, 100th=100}
102th
104th
101th
103th
100th
也证明Hashtable或者HashMap不是所谓的有序排列。keys()遍历Hashtable的键,同样的elements()也会遍历Hashtable的值。
为了内容的延续性我们放到后面来讲fail-fast机制。接下来还是看两个集合的区别。
- 扩容机制不同
在此之前,先看一下Hashtable的构造函数:
public Hashtable(int initialCapacity, float loadFactor) { if (initialCapacity < 0) throw new IllegalArgumentException("Illegal Capacity: "+ initialCapacity); if (loadFactor <= 0 || Float.isNaN(loadFactor)) throw new IllegalArgumentException("Illegal Load: "+loadFactor); if (initialCapacity==0) initialCapacity = 1; this.loadFactor = loadFactor; table = new Entry<?,?>[initialCapacity]; threshold = (int)Math.min(initialCapacity * loadFactor, MAX_ARRAY_SIZE + 1); } public Hashtable(int initialCapacity) { this(initialCapacity, 0.75f); } public Hashtable() { this(11, 0.75f); } public Hashtable(Map<? extends K, ? extends V> t) { this(Math.max(2*t.size(), 11), 0.75f); putAll(t); }