HashMap 和 Hashtable 的 6 个区别,最后一个没几个人知道!
hashmap 和 hashtable 是 java 开发程序员必须要掌握的,也是在各种 java 面试场合中必须会问到的。
但你对这两者的区别了解有多少呢?
现在,栈长我给大家总结一下,或许有你不明朗的地方,在栈长的指点下都会拨开迷雾见晴天。
1、线程安全
hashtable 是线程安全的,hashmap 不是线程安全的。
为什么说 hashtable 是线程安全的?
来看下 hashtable 的源码,hashtable 所有的元素操作都是 synchronized 修饰的,而 hashmap 并没有。
public synchronized v put(k key, v value); public synchronized v get(object key); ...
2、性能优劣
既然 hashtable 是线程安全的,每个方法都要阻塞其他线程,所以 hashtable 性能较差,hashmap 性能较好,使用更广。
如果要线程安全又要保证性能,建议使用 juc 包下的 concurrenthashmap。
3、null
hashtable 是不允许键或值为 null 的,hashmap 的键值则都可以为 null。
那么问题来了,为什么 hashtable 是不允许 key 和 value 为 null, 而 hashmap 则可以?
hashtable put 方法逻辑:
public synchronized v put(k key, v value) { // make sure the value is not null if (value == null) { throw new nullpointerexception(); } // makes sure the key is not already in the hashtable. entry<?,?> tab[] = table; int hash = key.hashcode(); ... }
hashmap hash 方法逻辑:
static final int hash(object key) { int h; return (key == null) ? 0 : (h = key.hashcode()) ^ (h >>> 16); }
可以看出 hashtable key 为 null 会直接抛出空指针异常,value 为 null 手动抛出空指针异常,而 hashmap 的逻辑对 null 作了特殊处理。
4、实现方式
hashtable 的继承源码:
public class hashtable<k,v> extends dictionary<k,v> implements map<k,v>, cloneable, java.io.serializable
hashmap 的继承源码:
public class hashmap<k,v> extends abstractmap<k,v> implements map<k,v>, cloneable, serializable
可以看出两者继承的类不一样,hashtable 继承了 dictionary类,而 hashmap 继承的是 abstractmap 类。
dictionary 是 jdk 1.0 添加的,貌似没人用过这个,栈长我也没用过。。
5、容量扩容
hashmap 的初始容量为:16,hashtable 初始容量为:11,两者的负载因子默认都是:0.75。
/** * constructs a new, empty hashtable with a default initial capacity (11) * and load factor (0.75). */ public hashtable() { this(11, 0.75f); } /** * constructs an empty <tt>hashmap</tt> with the default initial capacity * (16) and the default load factor (0.75). */ public hashmap() { this.loadfactor = default_load_factor; // all other fields defaulted }
当现有容量大于总容量 * 负载因子时,hashmap 扩容规则为当前容量翻倍,hashtable 扩容规则为当前容量翻倍 + 1。
6、迭代器
hashmap 中的 iterator 迭代器是 fail-fast 的,而 hashtable 的 enumerator 不是 fail-fast 的。
所以,当其他线程改变了hashmap 的结构,如:增加、删除元素,将会抛出 concurrentmodificationexception 异常,而 hashtable 则不会。
可以来看下这个区别的演示:
/** * 微信公众号:java技术栈 **/ public static void main(string[] args) { map<string, string> hashtable = new hashtable<>(); hashtable.put("t1", "1"); hashtable.put("t2", "2"); hashtable.put("t3", "3"); enumeration<map.entry<string, string>> iterator1 = (enumeration<map.entry<string, string>>) hashtable.entryset().iterator(); hashtable.remove(iterator1.nextelement().getkey()); while (iterator1.hasmoreelements()) { system.out.println(iterator1.nextelement()); } map<string, string> hashmap = new hashmap<>(); hashmap.put("h1", "1"); hashmap.put("h2", "2"); hashmap.put("h3", "3"); iterator<map.entry<string, string>> iterator2 = hashmap.entryset().iterator(); hashmap.remove(iterator2.next().getkey()); while (iterator2.hasnext()) { system.out.println(iterator2.next()); } }
输出信息:
t2=2 t1=1 exception in thread "main" java.util.concurrentmodificationexception at java.util.hashmap$hashiterator.nextnode(hashmap.java:1442) at java.util.hashmap$entryiterator.next(hashmap.java:1476) at java.util.hashmap$entryiterator.next(hashmap.java:1474) at cn.javastack.test.main(test.java:37)
看到了吧?
所以,这条同样也是 enumeration 和 iterator 的区别。
最后一点有几个人知道?知道的给栈长点个赞回应一下,不知道的有收获的也点一个赞支持一下吧。
有收获?转发给更多的人吧!
本文原创首发于微信公众号:java技术栈(id:javastack),关注公众号在后台回复 "java" 可获取更多,转载请原样保留本信息。