1、首先拿到当前elementData的数组大小记为size
2、接着,如果elementData数组为空数组,则会将size + 1 与 默认大小DEFAULT_CAPACITY = 10 取最大值,如果里面存有元素,则不会进行比较后赋值
3、只有当数组满载情况下会触发扩容算法 (elementData数组有元素时minCapacity = elementData.length + 1,elementData为空数组时,minCapacity = 10)
4、扩充集合容器算法:拿到当前elementData数组大小通过右移1位位运算后 + elementData数组大小,记为newCapacity(新容器容量)。如果newCapacity < minCapacity(默认容量 或者 当前elementData数组大小 + 1) 会将 minCapacity 赋值给 newCapacity。容器的最大容量为Integer.MAX_VALUE - 8,如果预设定的容量 > 最大值,则强制设为最大值。定好容器容量后copy一个新容量的数组并将之前老的元素存储到新数组中。
5、容器扩容完后,进行添加元素到新数组中
1、首先会检查插入的角标是否合法,如果角标 > 数组长度 或者 角标 < 0,都会报角标越界异常
2、同样扩容规则和add(E e)的扩容规则一致
3、通过System.arraycopy(Object[] src, int srcPos, Object[] dest, int destPos, int length),方法进行拷贝,srcPos从指定原数组位置开始取元素,destPos从目标数组位置开始存元素,length取的元素长度,之后将得到新数组后,会预留指定元素位置用于插入新值
1、先检查下标合法性
2、取出移除指定位置的元素,用于返回给客户端
3、同样移除操作也是借助于System.arraycopy()方法进行复制操作
4、操作完后,将数组大小进行–size,然后把最后一个元素置空等待GC回收内存
1、该方法与remove(int index)方法移除的逻辑大致相同
2、根据指定的object去移除元素,是先根据指定的object找到在数组中的下标,之后再通过下标去移除元素
1、内部调用了LinkedList.linkLast(E e)
2、跟进linkLast(E e):
----a、定义一个节点l
(作用类似交换2个变量的temp变量)用于记录last
节点指向的节点,可进行后面newNode(新插入元素节点)插入位置的确定。同时把l
节点指向last
节点(作用可在步骤f查看)
----b、接着创建一个newNode
节点,并为newNode
指定前一个节点为l
。接着把last
节点单指向newNode
节点(作用可在步骤e、f查看)
----c、如果当前集合是空的,那么直接将first
节点指向newNode
节点。
----d、如果在插入之前集合存在元素,那么步骤b已经确定了newNode
节点的前一个节点为l
,接下来设置l
的下一个节点是newNode
节点,这样就确定了l
节点和newNode
节点的位置关系。
----e、由于在步骤b结束后,会重新让last
节点指向newNode
节点,那么在步骤d结束后,确定了newNode
节点位置,于此同时last
的位置也已确定。
----f、l
节点位置的确定:在该方法一开始就让l
节点指向上一次添加到集合中元素的节点位置及last
节点,而每次添加元素时,last
节点是位置已经确定。
3、例:第一次插入元素,那么last
节点指向newNode
节点,然后让first
指向newNode
节点,即newNode
节点位置已经确定好同时last
节点指向newNode
节点,所以last
节点也确定位置。接着插入第二个元素时,last
节点指向第一个已经确定的位置,并让l
节点指向last
,致使l
节点的位置也确定,通过步骤d操作就确定了newNode
节点的位置,后面插入元素以此类推
4、添加元素的流程图:
1、该方法内部调用addAll(int index,Collection<? extends E> c)
2、继续跟进:如果当前集合不为空时,调用了node(int index)
,其内部是进行二分法查找(由此发现,LinkedList查找元素性能低),找到指定位置的节点,目的是在后面进行设置指定节点与插入元素的一个位置关系。
3、确定了插入元素节点的前一个节点,然后进行遍历插入的集合元素,并且对元素节点建立链关系(建立链关系与add(E e)
方式雷同)
1、删除原理:同样是通过调用node(int index)
进行二分法查找指定位置的元素节点,然后开始对指定的节点进行断链、置null,然后让分开的两段链相互链接形成一个整链,最后使其成为孤立的null对象,最后由GC回收。
2、在remove(int index)
中调用了unlink(Node<E> x)
,该方法是做了断链、置空、连接链操作
补充:
1、<< 左移1位 => 原数 * 2,左移2位 => 原数 * 2 * 2…以此类推(左移 右边添0)
2、>> 右移1位 => 原数 / 2 取整,右移2位 => 原数 / 2 / 2… 以此类推(右移 左边添0)