HashMap和HashTable
- 线程安全: HashMap是非线程安全的,HashTable是线程安全的,内部方法使用synchronized修饰,但是如果要保证线程安全推荐使用ConcurrentHashMap
- 效率: HashMap效率高,HashTable基本被淘汰
- null Key 和 null Value: HashMap允许,只能有一个null Key , HashTable不允许,会抛出空指针异常
- 初始容量大小和扩容大小: (1)HashMap初始大小为16,扩容为原来2倍,HashTable初始容量为11,扩容为原来的2n+1;(2)如果指定大小,HashTable会使用指定的大小,HashMap会将其扩充为2的幂次方大小
- 底层结构: HashMap采用数组+链表+红黑树的数据结构,而HashTable是数组+链表
说说HsahMap的大小为什么是2的幂次方
因为hash值的取值范围在-21亿到21亿之间,这么大的范围,很难出现hash碰撞,但是数组的长度不能达到这么大,否则内存会不够用,因此,在计算出hash值后,还需要计算对应的数组下标,用hash值对数组长度进行取模运算,得到的结果就是数组下标,当数组长度为2的次幂的时候,hash%length
和hash&(length-1)
所得的结果相等,并且与操作效率要高,因此HashMap的长度是2的次幂。在指定参数的时候构造2次幂如下:
static final int tableSizeFor(int cap) {
int n = cap - 1;
n |= n >>> 1;
n |= n >>> 2;
n |= n >>> 4;
n |= n >>> 8;
n |= n >>> 16;
return (n < 0) ? 1 : (n >= MAXIMUM_CAPACITY) ? MAXIMUM_CAPACITY : n +
1;
}
将最高位的前一位置为1,其他都变成0,这样就完成了
HashMap和HashSet
HashSet底层是基于HashMap实现的,HashSet中很多方法都是直接调用的HashMap,HashSet使用成员对象来计算HashCode值,对于俩个对象来说,Hashcode可能相等,因此还需要通过equals来比较。
==和equals
- 对于基本类型来说,==比较的是值是否相等
- 对于引用类型来说,==比较俩个引用是否指向同一个内存地址;如果equals没有被重写,会比较俩个对象的内存地址是否相等,如果被重写,比较的是地址里面的内容