一.Map接口下的集合的特点
1.存储的集合都是双值,即都为key-value结构。
2.无序(TreeMap可以排序),键不能重复,值可以重复,没有继承Collection接口。
HashMap | 异步 线程不安全 只允许一条记录的键为NULL |
Hashtable | 同步 线程安全 key和value不可以为空 |
TreeMap | 可以排序 不允许键为NULL |
二、哈希
由于Map接口下所有元素存放的位置都是由key决定的,那么通过key计算存储位置的方法称作哈希算法,计算的时候就会出现多个key计算出的位置相同这种情况称作哈希冲突。那么解决哈希冲突有什么办法?
1.开放定址法:
线性探测再散列
平方探测再散列
随机探测再散列
2.链地址法:
哈希地址为i的元素构成一个称为同义词链的单链表
链地址法适用于经常进行插入和删除的情况。
3.再哈希
发生哈希冲突时,对地址再次哈希,种方法不易产生聚集,但增加了计算时间。
4.建立公共溢出区
将哈希表分为基本表和溢出表两部分,凡是和基本表发生冲突的元素,一律填入溢出表
三、Map下的集合元素的存储位置都和key有关,这个集合使用的是什么哈希算法?
1.TreeMap
底层是红黑树(也是它有序的原因),采用的key的hashCode()。
2.HashMap
HashMap添加元素时,是使用自定义的哈希算法,有比较多的扰动处理,使散列后的地址分布更加均匀,能有效降低发生哈希冲突的概率。
3.HashTable
Hashtable没有自定义哈希算法,而直接采用的key的hashCode()。
四、Hashcode() 和equals()方法
1.这两个方法分别有什么作用?
equals()方法是用来判断其他的对象是否和该对象相等。
hashCode()方法给对象返回一个hash code值(这个值一般作为除留余数法的被除数)。
2.两者有什么联系?
hashCode主要用于提升查询效率,来确定在散列结构中对象的存储地址;
重写equals()必须重写hashCode(),二者参与计算的自身属性字段应该相同(关于这部分感兴趣可以看之前我写过的一篇博文:https://blog.csdn.net/weixin_43729854/article/details/104649481);
hash类型的存储结构,添加元素重复性校验的标准就是先取hashCode值,后判断equals();
equals()相等的两个对象,hashcode()一定相等;
反过来:hashcode()不等,一定能推出equals()也不等;
hashcode()相等,equals()可能相等,也可能不等。
五、集合中一些特殊属性值设置的用意:
1.加载因子的大小与哈希冲突之间的关系?
加载因子越大,填满的元素越多,好处是,空间利用率高了,但是冲突的机会加大了.
加载因子越小,填满的元素越少,好处是:冲突的机会减小了,但是空间浪费多了.
2.HashMap中table.length的大小为什么保持为2的幂?
这里不得不提一个数学公式:
x被y-1(y是2的幂)按位& 相当于 x被y取余 <位运算比除法效率高>
①HashMap 中则通过 h&(length-1) 的方法来代替取模,同样实现了均匀的散列,但效率要高很多,这也是 HashMap 对 Hashtable 的一个改进。
②保证了散列的均匀:length 为2的整数次幂的话,为偶数,这样 length-1 为奇数,奇数的最后一位是1,这样便保证了 h&(length-1) 的最后一位可能为0,也可能为1(这取决于h的值),即与后的结果可能为偶数,也可能为奇数,这样便可以保证散列的均匀性,而如果 length 为奇数的话,很明显 length-1 为偶数,它的最后一位是0,这样 h&(length-1) 的最后一位肯定为0,即只能为偶数,这样任何hash值都只会被散列到数组的偶数下标位置上,这便浪费了近一半的空间,因此,length 取2的整数次幂,是为了使不同 hash 值发生碰撞的概率较小,这样就能使元素在哈希表中均匀地散列。
六、浅析HashMap和HashTable的异同
| Hashtable | HashMap |
继承的父类和接口有什么相同和不同之处 | 继承自Dirctionary | 继承自AbstractMap |
均实现了Map接口 | ||
默认容量 | 11 | 16 |
Table的初始化时机 | 在构造函数初始化 | 在第一次put()初始化hash数组 |
并发操作,集合是否是线程安全的 | 安全 | 不安全 |
数据遍历的方式 | Iterator and Enumeration | Iterator |
是否支持fast-fail(快速失败机制) | JDK8及以后支持 | 支持 |
是否可以添加重复的key | 不可 | 不可 |
是否接受值为null的Key 或Value? | 不允许有null键和null值
| 允许出现一个null键,可以存在一个或者多个键的值都为null |
根据hash值计算数组下标的算法 | 直接使用对象的hashCode再使用除留余数发来获得最终的位置 | key的hash值高16位不变,低16位与高16位异或作为key最终的hash值 |
Entry数组的长度 | 默认是11 | 默认是16 |
LoadFactor负荷因子 | 0.75 | |
负荷超过(loadFactor * 数组长度)时,内部数据的调整方式 | 容量变为原来的2n+1 | 容量变为原来的2倍 |
|