1.ArrayList扩容规则
知识点1:无参构造器的初始值为0

知识点2:第一次扩容就会创建一个长度为10的数组
第二次后扩容就会是上次的1.5倍(第二次数组长度就是10*1.5=15
注意:新的数组会代替旧的数组,旧的数组会被垃圾回收掉)
第二次扩容计算:
15>>1
7
15+7
22
前20次扩容的数组长度的打印:

addAll():
1.list如果小于10,第一次扩容是10;
2.扩容规则:下次扩容的大小和数组的长度中取较大值;


总结:

迭代器:




failSafe:

重复刚才的过程:

**34-35 .FailFast源码分析
2.LinkedList

ArrayList:是基于内存存储连续存储 可以通过简单的计算可以算出内存地址
比如:第一个元素地址是0 每个地址都是30个字节 第四个下标的地址是:0+4*30=120
LinkList:比如也找到4,先从1找到2的地址,然后从2找到3的地址,从3找到4的地址;

**36.04.00 -05.26 讲解源码


随机查询:AraryList性能更好
后面一样查询性能
LinkedList中间插入慢的原因:查找需要一个一个找到,极其消耗性能
ArrayList头部插入或者其他非尾部查询需要复制一份,然后进行数据替换,性能比较慢

** 38 空间占用原理讲解
3.HashMap
3.1 HashMap的实现原理


计算原则:a 进行hashcode 97,然后二次hash得到 97 ,然后将97 和 数组长度16 进行取模得到1
这时候1就是a的下标

ArrayList获取a需要遍历查询,这种情况HashMap效率高的多
3.2 链表过长的解决方案
链表过长的解决方案:
1.扩容 当数组大于3/4被使用就会被扩容(数组长度是16的话,链表有13个元素就会被扩容
注意:扩容之后下标需要重新计算 如图1)
2.红黑树
需要同时满足两个条件:1.链表长度大于8 2.数组容量必须大于64 如图2
红黑树特点:是二叉树,左边小右边大,时间复杂度是O(logn),效率比链表高
注意:链表查询的时间复杂度O(n) 链表(node)占用的内存没有红黑树(TreeNode)多
正常情况下链表的长度不会大于8,主要防止黑客恶意攻击影响整个系统的性能 如图3
红黑树何时退化成链表:
图1.
图2.


图3.

图4.

退化成链表:

图5
3.3 索引是如何计算的



分布比较均匀的情况(正例):

分布不均匀的情况(反例):

原因:这些数据第一位都相同导致对16进行取模得到的数字都一样
解决方案:以jdk1.8为例

添加二次hash后,反例变均匀:

图6.








3.5 HashMap1.7和1.8的不同

注意:扩容是添加完之后进行扩容



注意:1.7扩容的问题:扩容后遵循 头插法导致扩容之后顺序变了,这就会导致死链问题
1.8在扩容计算node索引时,会优化:
按位与计算:如何是0则不用动位置,如果不为0则计算新的位置旧的位置+按位索引
3.6 HashMap负载因子的设计


注意:类型设置为Thread

注意:多线程很有可能出现丢数据的问题,如上图这两个都有可能同时运行631行代码,导致前面的key被覆盖。
**p53.1.7死链



注意:1.字符串如果多个可以通过这个散列公式计算出对应的hashcode,得到足够混匀的hash值
2.31优化更好可以用按位与进行运算
文章详细介绍了ArrayList的扩容规则,初始为0,首次扩容为10,后续每次1.5倍增长。LinkedList的查询和插入性能特点,以及HashMap的实现原理,包括二次哈希解决冲突,链表转红黑树的策略,以及1.7和1.8版本的区别。同时提到了HashMap的线程安全问题和死链现象。
3753

被折叠的 条评论
为什么被折叠?



