欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

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

程序员文章站 2024-01-25 09:06:28
HashMap 和 Hashtable 是 Java 开发程序员必须要掌握的,也是在各种 Java 面试场合中必须会问到的。 但你对这两者的区别了解有多少呢? 现在,栈长我给大家总结一下,或许有你不明朗的地方,在栈长的指点下都会拨开迷雾见晴天。 1、线程安全 Hashtable 是线程安全的,Has ......

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