1.HashMap与HashTable相同点
- 1.二者都是以哈希表(数组+链表)数据结构存储数据.
- 2.二者都可以进行数组扩容
2.HashMap与HashTable区别
-
1.是否线程安全
HashMap不是线程安全的,HashTable是线程安全的;【HashTable内部的方法基本都使用了synchronized关键字修饰】
注意:现在HashTable在我们的开发中很少很少使用。如果你要保证线程安全,推荐使用ConcurrentHashMap -
2.效率
因为线程安全的问题,HashMap要比HashTable的效率高一点。 -
3.对于Null Key和Null Value的支持
HashMap中,null可以作为key,但是这样的key只能有一个;可以有一个或者多个键对应的value为null;
HashTable中不支持key为null,如果put使用null,那么就会抛出NullPointerException异常; -
4.初始容量和每次扩充容量的大小不同
HashMap创建的时候如果不指定容量大小,初始容量大小为16,之后每次扩充,容量变为原来的2倍;
HashTable创建的时候如果不指定容量大小,初始容量大小为11,之后每次扩充,容量会变为2n + 1;
HashMap创建的时候给定初始容量大小,HashMap 会将其扩充为2的幂次方大小(HashMap 中的tableSizeFor()方法保证,下面给出了源代码)。也就是说 HashMap 总是使用2的幂作为哈希表的大小,后面会介绍到为什么是2的幂次方。 -
5.继承的父类不同
HashMap继承自AbstractMap类。但二者都实现了Map接口。
Hashtable继承自Dictionary类,Dictionary类是一个已经被废弃的类(见其源码中的注释)。父类都被废弃,自然而然也没人用它的子类Hashtable了 -
6.支持的遍历种类不同:
HashMap只支持Iterator遍历,而HashTable支持Iterator和Enumeration(枚举)两种方式遍历 -
7.计算hash值方式不同
为了得到元素的位置,首先需要根据元素的 KEY计算出一个hash值,然后再用这个hash值来计算得到最终的位置。
①:HashMap有个hash方法重新计算了key的hash值,因为hash冲突变高,所以通过一种方法重算hash值的方法:
static final int hash(Object key) {
int h;
return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}
注意:这里计算hash值,先调用hashCode方法计算出来一个hash值,再将hash与右移16位后相异或(异或计算方式:相同为0,不相同为1,可以理解为不进位相加),从而得到新的hash值。
例子:
十进制:3254818
注意:int类型 占4byte 32位
处理数据
二进制:11 0001 1010 1010 0010 0010 (22位,不足32位,则补0到32位)
0000 0000 0011 0001 1010 1010 0010 0010 (32位)
h>>>16 无符号右移16位
0000 0000 0000 0000 0000 0000 0011 0001
^ 异或操作:相同为0,不相同为1,可以理解为不进位相加
数据处理完毕,开始进行异或操作
h = key.hashCode() ^ (h >>> 16)
0000 0000 0011 0001 1010 1010 0010 0010 ( h = key.hashCode())
^ (异或)
0000 0000 0000 0000 0000 0000 0011 0001 (h >>> 16)
结果为:
0000 0000 0011 0001 1010 1010 0001 0011
3245803 (十进制结果)
②:Hashtable通过计算key的hashCode()来得到hash值就为最终hash值。
- 8.解决hash冲突方式不同(地址冲突)
JDK1.8 以后的 HashMap 在解决哈希冲突时有了较大的变化,当链表长度大于阈值(默认为8)时,将链表转化为红黑树,以减少搜索时间;
而在HashTable中, 都是以链表方式存储