当前位置: 移动技术网 > IT编程>开发语言>Java > HashMap 和 Hashtable 的 6 个区别,最后一个没几个人知道!

HashMap 和 Hashtable 的 6 个区别,最后一个没几个人知道!

2018年12月05日  | 移动技术网IT编程  | 我要评论

南昌二中吧,邪神魔掌,ca1570

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" 可获取更多,转载请原样保留本信息。

如对本文有疑问,请在下面进行留言讨论,广大热心网友会与你互动!! 点击进行留言回复

相关文章:

验证码:
移动技术网