List集合
List接口
ArrayList
结论
底层原理
执行的代码
1.无参构造
elementData
就是ArrayList
底层元素存放的数组2.有参构造
两个只是构造方法不一样,但是后面的
add
和grow
是一样的只不过是直接将
elementData初始化大小为8的数组
3.集合
add
方法判断当前的
capacity
容量是否充足,size
当前集合的元素的数量(每一次进入 add 方法的时候,size的位置就是存放add的元素的下标,存放完之后 size++),第一次 add ,size 为 0
进入
ensureCapacityInternal
确认容量内部 的方法,modCount
记录当前的集合被修改次数,防止多个线程修改,抛出异常,fail-fast如果 if 成立,就表示 需要的最小容量已经大于当前容量了,所以当前容量需要扩大,进入
grow
扩容
minCapacity
指的是源数组中存储的元素个数加上将要存储的元素个数,这里第一次add()时,minCapacity为1,数组的长度为0,数组内存不够,故进行扩充
elementData.length
是数组(集合)容量的大小扩容,进入
grow
方法,最后通过Array.copyOf
方法复制旧数组并且扩容返回新的数组
右移,相当于是除以2,左移,相当于是乘以2
所以
newCapacity = oldCapacity + (oldCapacity >> 1)
就是相当于 扩容了
oldCapacity
的1.5倍下面代码的第一个
if
判断,是因为第一次扩容为 10 的时候,minCapacity=10,newCapacity、oldCapacity 都为0
,这是对一次进行扩容的弥补措施
ArrayList和Vector区别
Vector
线程安全的,synchronized
加锁
底层原理
执行代码
1.无参构造
this
就是调用本类的 构造器
所以,我们可以指定 有参构造,或者两个参数的构造方法
capacityIncrement
是第一次进行扩容的大小2.进入
add
方法跟
ArrayList
大体一样3.满足条件。进入
grow
扩容方法
capacityIncrement
扩容的大小,创建vector
没有指定的话,默认是 0那么
capacityIncrement
一辈子就都是 0 了,所以每一次扩容都是oldCapacity + oldCapacity
,2倍如果创建
vector
的时候指定了capacityIncrement
,那么之后的每一次扩容都是按照capacityIncrement
大小进行扩容,就不是 2 倍了
LinkedList
双向链表
底层原理
执行代码
1.无参构造
就是简单的初始化 属性
有参数的构造E 是创建 linkList 对象指定的泛型
2.
add
方法
linkLast
方法就是,将元素 element 添加到 linkList 链表的 last 位置就是一个简单的算法逻辑,就是 l 是复制的 last,然后创建一个新的节点,存储 add 元素,新节点的 prev 指向 l(也就是上次的last),然而 last 被赋值为新节点 newNode
这就完成了 last 还是 last,并且 newNode 的 prev 指向的是上一次的 last
3.
remove
方法默认的是 删除第一个节点
进入
unlinkFirst
删除节点的方法,返回值是 删除的元素 element如果不加 final 的话,同样会被 gc 干掉
ArrayList和LinkedList区别
两者都是线程不安全的
链表因为只能从头节点开始遍历,只能通过顺次指针访问,查询效率低,所以 查询和修改某一个节点 性能较差
因为 链表 不同node节点对象是通过 指针 连接起来的,是不连续的内存地址
链表则必须是顺序访问,不能随机访问(必须从头节点开始进行遍历,因为不知道内存地址)
底层维护的是 Node 对象
链表可以随意扩大容量
ArrayList
底层是维护的一个数组,数组是连续的内存地址,所以使用方便 ,查询效率 比链表 高数组可以随机访问其中的元素 (因为内存地址是连续的,可以通过计算得出访问的元素的地址)
数组则不能随便扩容,只能通过 copy 重新创建一个数组进行转移扩容
本文来自博客园,作者:小小俊少,转载请注明原文链接:https://www.cnblogs.com/xxjs168/articles/17481743.html