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。
创建时指定初始容量,则初始大小为指定的大小