<>HashMap与Hashtable区别

1.(同分性)Hashtable是同步的,里面的方法都加了synchronized,所以是线程安全的,但是效率会很低,因为所有的线程进来都要排队。所以一般选用concurrentHashMap来实现线程安全,它是使用分段锁来实现的,不是全部锁住。

2.(继承的父类不同)hashtable是继承了Dictionary类,而hashMap是继承了AbstractMap类

3.(对null key 和null
value支持不同)hashtable不允许null值(key和value都不行),hashmap允许null值(key和value都可以)。这样的key只有一个,而value可以多个。
从put()方法体现的:

key为null的话执行hashcode还是会报空指针异常。

hashmap的:

如果key == null,则直接定位为0

4.(初始化和扩容方式不同)(hashtable默认为11,默认加载因子:0.75),而hashmap默认为16
hashtable是在构造方法上初始化的,而hashmap是在进行第一次调用put()的时候再在resize()方法里才进行初始化。hashtable每次扩容为原来的2n+1倍,而hashmap是原来的2倍。

5.hash方法不同。
hashMap:

高16位向低16位右移,让高位和低位同时进行运算,为什么16位?因为是整型(32位),为的是让计算出的hash值分布均匀。避免只有低位相同的hash进行严重的碰撞。

hashtable:
直接进行hashcode

计算index不同:
hashtable:一开始就将符号位去掉,主要是取余操作:

hashmap:容量要为2的n次方,这跟与运算相关,保证算出来的index是在(0-n-1)的范围。

<>HashMap:

0.75:折中平衡,太高则减少空间的浪费,但是会增加查找的消耗,泊松概率

java7容易碰到死锁:

它的扩容是采用头插法造成死循环:

java7 hash表+链表
java8 hash表+红黑树

成树的阈值为8的原因:服从泊松分布,超过8的概率就很小了
java8的扩容是按顺序扩容的

两者都是List接口的实现类,即代表插入的元素是有序和可重复的!两者都不是线程安全的。

<>ArrayList

(底层主要是用动态数组来实现的,所以存储顺序是连续的,它的查找比较快,但是在插入和删除的时候,如果是在数组的中间添加(删除)数组则需要把其他的元素向后或者向左移动,主要是通过system.arraycopy()来实现数组的移动的,所以就比较耗时。但是如果直接在数组后面移动就直接在数组后面添加即可)

* 如果通过无参构造的话,初始数组容量为0,当真正对数组进行添加时,才真正分配容量,默认为10。
* 实现了Serializable接口,因此它支持序列化,能够通过序列化传输;
* 实现了RandomAccess接口,支持快速随机访问,实际上就是通过下标序号进行快速访问;
* 实现了Cloneable接口,能被克隆。
* 扩容升为原来的1.5倍,(10*1.5=15)每次扩容都是通过Arrays.copyOf(elementData, newCapacity)
这样的方式实现的。
<>LinkList

(底层采用了双向链表实现,它还实现了Deque接口,存储地址是不连续的,每个存储地址是通过指针来指向的,查找的时候需要遍历链表,所以比较慢,但插入和删除的时候不需要移动其他元素,所以就比较快,由于是双向链表,内部针对查找进行了优化,当查找的元素get(intdex)时会进行判断,当index
< size()/2就从左往右查询,当index > size()/2时就从右往左查询,但还是很很慢,链表这边主要是通过for来遍历链表的)

* LinkList默认初始化为空。
<>HashMap

put()的过程(拉链法):桶位置是根据index=(n-1)&hash计算的
1.当Node数组没被初始化的时候,则初始化容量为16,并将threshold初始化为12.
2.如果key==null,则计算hash为0,直接定位在桶为0的位置上

3.根据index找到桶位置,如果桶位置没有元素,则直接new一个Node并插入,看hashmap中的元素是否超过阈值,超过则调用resize()进行2倍扩容,新建一个2倍大小的数组,将老的数组中元素复制到新的数组里,老的数组被GC。

4.如果有元素,则取出节点p,判断传入的值的key以及key所产生的hash和取出来的p的key以及hash值是否相等,相等则进行替换,不相等,则判断取出的p是否是红黑树,(如果不是,则直接插入到链表末尾,然后判断后面元素是否超过8个,如果超过8个且Node数组空间元素超过64个就将单链表转化成双向链表再转换成红黑树,如果没有超过8个,就调用resize()进行扩容),如果是则采用红黑树的插入。

红黑树特点:

* 根结点一定是黑色
* 红色结点下面如果有孩子的话,一定是两个黑色结点
* 每次往红黑树里面插入元素的话,一定是红色
* 结点到其叶子结点黑色结点的数量一定相同

技术
下载桌面版
GitHub
Gitee
SourceForge
百度网盘(提取码:draw)
云服务器优惠
华为云优惠券
腾讯云优惠券
阿里云优惠券
Vultr优惠券
站点信息
问题反馈
邮箱:[email protected]
吐槽一下
QQ群:766591547
关注微信