Java面试之Java集合3——HashMap和HashTable的区别

HashMap和HashTable的区别

  HashMap HashTable
线程是否安全 线程不安全 线程安全
效率 因为线程不安全,所以性能相对更高 基本被淘汰,不要使用了
对null key和null value的支持 可以存储null的key和value,但只能有一个null作为键,可以有多个null为键值 不能存储带有null的key和value,否则抛出NullPointerException
初始容量大小和每次扩容大小 创建时不指定初始容量,则默认初始大小为16,每次扩充,容量变为原来的2倍。创建时指定初始容量,则初始大小会扩充为2的幂次方大小 创建时不指定初始容量,则默认初始大小为11,每次扩充,容量变为原来的2n+1。创建时指定初始容量,则初始大小为指定的大小
底层数据结构 在JDK1.8之后,当链表长度大于阈值(默认为8),会将链表转换成红黑树,减少搜索时间

HashMap

Map是用来存储键值对的。

  • HashMap没有使用同步锁,所以线程不安全,性能相对高一些,如果要线程安全可以使用ConcurrentHashMap。

  • HashMap支持key和value为null
public class Demo {
    public static void main(String[] args) {
        // HashMap允许key为null,但多个key为null的话,只会保留一个
        Map<String, String> map1 = new HashMap<>();
        map1.put(null, "1");
        map1.put(null, "2");
        System.out.println(map1);

        // HashMap允许多个value同为null
        Map<String, String> map2 = new HashMap<>();
        map2.put("1", null);
        map2.put("2", null);
        System.out.println(map2);
    }
}
/**
 * 打印结果:
 * {null=2}
 * {1=null, 2=null}
 */
  • HashMap的初始容量和扩充容量的值

如果不指定初始容量,那么HashMap的初始容量为16,每次扩充,变为原来的2倍,后面的每次扩充的结果都是2的幂次方。

如果指定初始容量,则会根据指定的大小扩充为2的幂次方大小。

其中关于tableSizeFor()方法的详解可以参考博客:https://blog.csdn.net/lw_zj_ywn/article/details/78282905

该方法的意思就是检查传入的初始值是否为2的幂次方,如果不是,则将其变为2的幂次方,比如输入10,那么该方法的返回值就是16。

可以将该方法提出来,然后传入值进行测试。

  • 在JDK1.8之后,当链表长度大于阈值(默认为8),会将链表转换成红黑树,减少搜索时间

putVal()方法的源码分析可以参考博客:https://blog.csdn.net/ljf199701/article/details/106309417

HashTable

  • HashTable中的方法使用了同步锁,所以线程安全。

  • HashTable中不允许key和value值任何一个为null,否则报空指针异常。

  • HashTable的初始容量和扩充容量

如果创建时不指定初始容量,则默认初始大小为11,每次扩充,容量变为原来的2n+1。

创建时指定初始容量,则初始大小为指定的大小

猜你喜欢

转载自blog.csdn.net/cnds123321/article/details/113704294