HashMap在平时用的较多,了解得也较多,当问起Hashtable时,脑子里一篇空白(没用过)。
下面记录一下这两者的区别:
1.继承关系
从图片中可以发现,HashMap继承了AbstractMap,Hashtable继承了Dictionary,两者继承的父类不同。还可以发现,两者都实现了Map,Cloneable,Serializable这三个接口。
2.Key和Value是否支持null
先看Hashtable
源码的注释写着key和value都不能为空。
再看HashMap
从注释可以看出key和value都可以为null;value可以与key值相关联,或者null,如果没有key的映射,可以返回null如果key或者value为null。
3.是否线程安全
HashMap是线程不安全的,Hashtable是线程安全的
这张图片是Hashtable的put方法,使用了synchronize修饰,Hashtable源码中还有许多方法使用了synchronize修饰来保证线程安全。
4.初始大小与扩容策略
Hashtable的初始大小是11,HashMap的初始大小是16
Hashtable的扩容策略是2n+1(原大小的2倍+1),HashMap的扩容策略是2n(原大小的2倍)。
5.底层数据结构(JDK1.8)
HashMap:
当hash冲突小于8时采用链表法存储,
当hash冲突大于8时采用红黑树存储,
当hash冲突小于6时转化为链表法存储,
原因之一:当hash冲突=8时,链表法的平均查询次数为n/2=4,红黑树的平均查询次数为logn=3,这时将链表存储结构转化为红黑树存储才有意义。
Hashtable:
始终链表方式存储。
6.方法
1 import java.util.*; 2 3 public class Test { 4 public static void main(String[] args) { 5 HashMap<String,String> hashMap = new HashMap<>(); 6 Hashtable<String,String> hashtable = new Hashtable<>(); 7 hashtable.put("Redis","端口6379"); 8 hashMap.put("time","时间会给我答案吗?"); 9 10 System.out.println(hashtable.get("Redis"));//端口6379 11 System.out.println(hashtable.contains("端口6379"));//true 12 System.out.println(hashtable.containsValue("端口6379"));//true 等价于contains 13 /** 14 * public boolean containsValue(Object value) { 15 * return contains(value); 16 *} 17 */ 18 System.out.println(hashtable.containsKey("Redis"));//true 19 20 System.out.println(hashMap.get("time"));//时间会给我答案吗? 21 System.out.println(hashMap.containsValue("时间会给我答案吗?"));//true 22 System.out.println(hashMap.containsKey("time"));//true 23 System.out.println(hashMap.put("nu",null));//true 24 } 25 }
可以看出Hashtable有contains方法,HashMap则没有