diff --git "a/docs/java\351\233\206\345\220\210/.keep" "b/docs/java\351\233\206\345\220\210/.keep" new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git "a/docs/java\351\233\206\345\220\210/01-java\351\233\206\345\220\210\344\271\213ArrayList\346\272\220\347\240\201\345\211\226\346\236\220/01-java\351\233\206\345\220\210\344\271\213ArrayList\346\272\220\347\240\201\345\211\226\346\236\220.md" "b/docs/java\351\233\206\345\220\210/01-java\351\233\206\345\220\210\344\271\213ArrayList\346\272\220\347\240\201\345\211\226\346\236\220/01-java\351\233\206\345\220\210\344\271\213ArrayList\346\272\220\347\240\201\345\211\226\346\236\220.md" new file mode 100644 index 0000000000000000000000000000000000000000..1dd01695fae78347737f2cde0f59cc8e9c61b872 --- /dev/null +++ "b/docs/java\351\233\206\345\220\210/01-java\351\233\206\345\220\210\344\271\213ArrayList\346\272\220\347\240\201\345\211\226\346\236\220/01-java\351\233\206\345\220\210\344\271\213ArrayList\346\272\220\347\240\201\345\211\226\346\236\220.md" @@ -0,0 +1,410 @@ +* #### 前言 +* #### 基本原理 +* #### 常用方法源码剖析 + * ##### add() + * ##### add(index,element) + * ##### set() + * ##### get() + * ##### remove(index) +* #### 数组扩容及元素拷贝 + * #### 总结 + * ##### 优点 + * ##### 缺点 + +*** + +> ### 前言 +#####     ArrayList 是我们日常开发中使用非常频繁的一个集合,今儿我们通过源码来看看它底层是怎么来实现的,了解了解它的优缺点和真正适合的场景。 + +*** + +> ### 基本原理 +#####     ArrayList ArrayList就是数组列表,主要用来装载数据,当我们装载的是基本类型的数据int,long,boolean,short,byte…的时候我们只能存储他们对应的包装类,它的主要底层实现是数组Object[]elementData。 +#####     先来看一下ArrayList的内部组成源码: +``` + + /** + * Default initial capacity. + * 默认容量 + */ + private static final int DEFAULT_CAPACITY = 10 ; + + /** + * Shared empty array instance used for empty instances. + * 用于空实例的共享空数组实例。在初始化时,你传进去的初始化大小为0,那么就用这个来做的处理。 + */ + private static final Object[] EMPTY_ELEMENTDATA = {}; + + /** + * Shared empty array instance used for default sized empty instances. We + * distinguish this from EMPTY_ELEMENTDATA to know how much to inflate when + * first element is added. + * 共享的空数组实例,用于默认大小的空实例,默认构造器使用的。 + */ + private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {}; + + /** + * The array buffer into which the elements of the ArrayList are stored. + * The capacity of the ArrayList is the length of this array buffer. Any + * empty ArrayList with elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA + * will be expanded to DEFAULT_CAPACITY when the first element is added. + * 用来存储元素的数组 + */ + transient Object[] elementData; // non-private to simplify nested class access + + /** + * The size of the ArrayList (the number of elements it contains). + * 数组的大小 + * @serial + */ + private int size; + +``` + +#####     再来看一下ArrayList的构造函数: +``` + + “第一个” + /** + * Constructs an empty list with an initial capacity of ten. + * 默认无参的构造函数,会给用来存储元素的数组赋值为一个空数组实例 + */ + //默认无参的构造函数, new ArrayList() 使用默认的构造函数来创建它, + //那么它会直接使用一个空的 Object [],初始大小是0, + //它有一个默认的初始化大小参数 DEFAULT_CAPACITY 是 10, + //当添加第一个元素时,这个空数据的大小才是10,我们也可以认为它给我们创建的默认的数据大小就是10 + public ArrayList() { + this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA; + } + + “第二个” + /** + * Constructs an empty list with the specified initial capacity. + * + * @param initialCapacity the initial capacity of the list + * @throws IllegalArgumentException if the specified initial capacity + * is negative + */ + //这个构造函数可以设置数组的容量, + //一般来说是可以预估出来数据的大小,比如几十个,一百个, + //那么我们在初始化的时候就把这个数字带进去,避免数据容量太小在后续插入数据的时候进行频繁的扩容,创建 //新的数组。 + public ArrayList(int initialCapacity) { + if (initialCapacity > 0) { + this.elementData = new Object[initialCapacity]; + } else if (initialCapacity == 0) { + this.elementData = EMPTY_ELEMENTDATA; + } else { + throw new IllegalArgumentException("Illegal Capacity: "+ initialCapacity); + } + } + + +“第三个” + /** + * Constructs a list containing the elements of the specified + * collection, in the order they are returned by the collection's + * iterator. + * + * @param c the collection whose elements are to be placed into this list + * @throws NullPointerException if the specified collection is null + */ + // 构造一个包含指定元素的列表 + public ArrayList(Collection c) { + elementData = c.toArray(); + if ((size = elementData.length) != 0) { + // c.toArray might (incorrectly) not return Object[] (see 6260652) + if (elementData.getClass() != Object[].class) + elementData = Arrays.copyOf(elementData, size, Object[].class); + } else { + // replace with empty array. + this.elementData = EMPTY_ELEMENTDATA; + } + } +``` + +*** + +> ### 常用方法源码剖析 +* ##### add() +``` + /** + * Appends the specified element to the end of this list. + * + * @param e element to be appended to this list + * @return true (as specified by {@link Collection#add}) + */ + public boolean add(E e) { + ensureCapacityInternal(size + 1); // Increments modCount!! + elementData[size++] = e; + return true; + } +``` +####     源码剖析:add()函数so easy,首先先校验一下当前ArrayList需不需要扩容,然后把数据的 size++ 位置设置为元素,最后返回true; + +####     来看一个案例解析: +``` +/** + * ArrayList + */ +public class ArrayListDemo { + public static void main(String[] args) { + List stringList = new ArrayList(); + + stringList.add("张三"); + stringList.add("李四"); + stringList.add("王五"); + } +} +``` +####     最开始 elementData = [],是一个空的数组,size = 0,当 list.add("张三") 时,elementData[0] = "张三",size++ 后,size 的值就为 1 。 +####     然后 list.add("李四"),elementData[1] = "李四",当size++ 后,size 的值为 2,此时 elementData 的数据就是 ["张三","李四"] 。 +####     依次类推,当 list.add("王五") ,elementData[2] = "王五",添加了王五这个数据后,elementData = ["张三","李四","王五"] ,size = 3。 + +**** + +* #### add(index,element) +``` +/** + * Inserts the specified element at the specified position in this + * list. Shifts the element currently at that position (if any) and + * any subsequent elements to the right (adds one to their indices). + * + * @param index index at which the specified element is to be inserted + * @param element element to be inserted + * @throws IndexOutOfBoundsException {@inheritDoc} + */ + public void add(int index, E element) { + rangeCheckForAdd(index); + ensureCapacityInternal(size + 1); // Increments modCount!! + System.arraycopy(elementData, index, elementData, index + 1, + size - index); + elementData[index] = element; + size++; + } +``` +####     源码剖析:rangeCheckForAdd() 先校验一下当前index是否越界,ensureCapacityInternal()校验当前ArrayList需不需要扩容,System.arraycopy()数组的移动,然后数组当前index赋值,数组大小加1。 + +####     来看一个案例解析: +``` +stringList.add(1,"赵六"); +``` +####     首先 rangeCheckForAdd(1) 会对传进来的 index 为 1 进行是否越界的处理 。接下来执行 ensureCapacityInternal(size + 1) 操作,是做数组扩容的,具体数据怎么扩容,此篇文章后面会解答。然后来到了比较重要的代码 ,对数组的数据进行移动 +``` + System.arraycopy(elementData, index, elementData, index + 1, + size - index); +``` +####     此时的index = 1 ,size = 3 , 我们来转化一下: +``` +System.arraycopy(elementData, 1, elementData, 1 + 1, + 3 - 1); + +=> + +System.arraycopy(elementData, 1, elementData, 2, + 2); +``` +####     那么这段代码表示的意思就是说 : +####     elementData 这个数组,从第1位开始(第二个元素)拷贝,拷贝2个元素,把他们拷贝到 elementData 这个数组(还是原来的这个数组)从第2位开始(第三个元素)。 + +####     然后 elementData[index] = element ,把 elementData[1] 设置成 “赵六”, +####     最后 elementData 的数据就是 ["张三","赵六","李四","王五"]。 +####     最后再 size++ 后,size的值 为 4。 + +*** + +* #### set() +``` + /** + * Replaces the element at the specified position in this list with + * the specified element. + * + * @param index index of the element to replace + * @param element element to be stored at the specified position + * @return the element previously at the specified position + * @throws IndexOutOfBoundsException {@inheritDoc} + */ + public E set(int index, E element) { + rangeCheck(index); + + E oldValue = elementData(index); + elementData[index] = element; + return oldValue; + } +``` +####    源码剖析: +####         1)rangeCheck(index) 校验当前传进来的index是否数据越界, +####         2) E oldValue = elementData(index) 先把当前index的元素拿出来,elementData[index] = element 数组当前index赋新传入的值, +####         3)返回之前index的旧元素; + +####     来看一个案例解析: +``` +String strTemp = stringList.set(2,"马七") +``` +####    首先先进行 rangeCheck(index),检查给的索引是否越界,此时数组的个数是4,传入的索引下标是2,数组index没有越界, +####    然后 E oldValue = elementData(index) 这段代码会先把索引为 2 这个位置的数据 “李四” 取出来,那么 oldValue = “李四”; +####    再然后把 elementData[2] = “马七”,此时 elementData = ["张三",“赵六”,“马七”,"王五"],最后把 oldValue 的数据 “李四” 返回。 + +*** + +* #### get() +``` + /** + * Returns the element at the specified position in this list. + * + * @param index index of the element to return + * @return the element at the specified position in this list + * @throws IndexOutOfBoundsException {@inheritDoc} + */ + public E get(int index) { + rangeCheck(index); + + return elementData(index); + } + + @SuppressWarnings("unchecked") + E elementData(int index) { + return (E) elementData[index]; + } +``` +####    源码剖析: +####        首先先校验index 是否越界,然后直接调用 elementData(index) 方法,这个方法就是调用数组的取值。由于 elementData[index] 是直接通过数组直接定位这个元素,然后直接获取这个元素的,这个也是ArrayList 性能最好的一个操作,优点。 + +####    案例: +``` +String strTemp1 = stringList.get(0); +``` +####    根据index定位直接返回"张三" + +*** + +* #### remove(index) +``` + /** + * Removes the element at the specified position in this list. + * Shifts any subsequent elements to the left (subtracts one from their + * indices). + * + * @param index the index of the element to be removed + * @return the element that was removed from the list + * @throws IndexOutOfBoundsException {@inheritDoc} + */ + public E remove(int index) { + rangeCheck(index); + + modCount++; + E oldValue = elementData(index); + + int numMoved = size - index - 1; + if (numMoved > 0) + System.arraycopy(elementData, index+1, elementData, index, + numMoved); + elementData[--size] = null; // clear to let GC do its work + + return oldValue; + } +``` +####    源码剖析: +####        1)首先还是会校验索引是否越界, + +####       2)然后取出索引位置的数据, + +####       3)然后根据删除位置来计算需要移动元素的数量, + +####       4)如果移动需要移动元素的数量大于0 ,则使用 System.arraycopy 进行元素的移动, + +####       5)然后再把最后一个元素设置为 null, + +####       6)最终返回 删除的元素。 + +####     案例: +``` + String strRemoveTemp = stringList.remove(1); +``` +####    remove(1),当前数组的长度 size 是 4 , oldValue = elementData(1) = "赵六"。 +####     numMoved = size - index - 1,numMoved = 4 - 1 -1 = 2,相当于要把后面的 “马七”,“王五” 都要往前面移动一位。 +####     接下来是 System.arraycopy(elementData, index + 1, elementData, index, numMoved) ,转换过来则为 System.arraycopy(elementData, 2, elementData, 1, 2)。 +####     意思是说把 elementData 数组中,从 index = 2 的位置开始的元素,一共有 2 个,拷贝到 elementData (还是原来的数组),从 index = 1 开始,进行拷贝。 +``` +拷贝前:elementData["张三","赵六","马七,"王五"] +拷贝后:elementData["张三","马七,"王五","王五"] +``` +####     然后再执行 elementData[--size] = null ,转化过来就是 elementData[3] = null ,把数组最后一个位置设置为 null。 +####     最后得到的 elementData = ["张三","马七","王五"]。 +####     最后再返回 oldValue “赵六”。 + +*** + +> ### 数组扩容及元素拷贝 +####     ArrayList 里面最关键的一块儿,就是扩容及元素的拷贝。 + +####    假设说我们现在用的数组是默认的大小,也就是10 ,现在数据里面已经装满了10个元素,此时数组的size =10,capacity = 10。 +####    此时我们要调用 add() 方法 插入一个元素,插入第11个元素的时候是不行的,因为数据已经满了,此时就需要扩容。 + + ####    我们在 add( ) 方法中可以看到这样一行代码 : +``` +ensureCapacityInternal(size + 1); // Increments modCount!! +``` +####     此时 ensureCapacityInternal(11),minCapacity = 11。 +``` +private void ensureCapacityInternal(int minCapacity) { + ensureExplicitCapacity(calculateCapacity(elementData, minCapacity)); + } +``` +####     调用 calculateCapacity(elementData, minCapacity) 后得到 minCapacity = 11 +``` +private static int calculateCapacity(Object[] elementData, int minCapacity) { + if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) { + return Math.max(DEFAULT_CAPACITY, minCapacity); + } + return minCapacity; + } +``` + +####     进入到 ensureExplicitCapacity(),会发现 minCapacity - elementData.length 是大于 0 的,所以会进入到 grow() 方法里面,这里面就会进行扩容。 +``` +private void ensureExplicitCapacity(int minCapacity) { + modCount++; + + // overflow-conscious code + if (minCapacity - elementData.length > 0) + grow(minCapacity); + } + + /** + * Increases the capacity to ensure that it can hold at least the + * number of elements specified by the minimum capacity argument. + * + * @param minCapacity the desired minimum capacity + */ + private void grow(int minCapacity) { + // overflow-conscious code + int oldCapacity = elementData.length; + int newCapacity = oldCapacity + (oldCapacity >> 1); + if (newCapacity - minCapacity < 0) + newCapacity = minCapacity; + if (newCapacity - MAX_ARRAY_SIZE > 0) + newCapacity = hugeCapacity(minCapacity); + // minCapacity is usually close to size, so this is a win: + elementData = Arrays.copyOf(elementData, newCapacity); + } +``` + +####     首先 + ####     oldCapacity = 10, + ####     newCapacity = oldCapacity + (oldCapacity >> 1), + ####     oldCapacity >> 1 相当于 oldCapacity/2 也就是 10 / 2 =5, +####     那么 newCapacity = 15。 +####     此时新的数组 就变成了可以容纳15个元素的数据,老的数组是 10个。最后使用 Arrays.copyOf() 工具方法来完成老数组到新数组的拷贝。 +####     看到这里你就会发现数组扩容它是怎么来扩的,是老数据的大小+ 老数组大小 >> 1(相当于除以2) 来计算出来新数组的 大小,再使用 Arrays.copyOf() 来实现数据的拷贝。 + +*** + +> ### 总结 + ####     `优点:` + ####         基于数组来实现,他在随机获取数组里的某个元素的时候,性能很高,他可以基于他底层对数组的实现来快速的随机读取到某个元素,直接可以通过内存地址来定位某个元素。 +####     `缺点:` + ####         1、若我们要频繁的向ArrayList 里面塞数据,会导致它频繁的数据扩容,会导致系统性能下降,所以说不要频繁的向ArrayList 插入数据。 + ####         2、数组你要是往数组的中间加一个元素,要把数组中那个新增元素后面的元素全部往后面挪动一位,所以说,如果你是往ArrayList中间插入一个元素,性能比较差,会导致他后面的大量的元素挪动一个位置。 +####     `使用场景:` + ####         1、如果你不会频繁的在里面插入一些元素,不会导致频繁的元素的位置移动、数组扩容,就是有一批数据,查询出来,灌入ArrayList中,后面不会频繁插入元素了,主要就是遍历这个集合,或者是通过索引随机读取某个元素,使用ArrayList还是比较合适的。 + ####         2、若果你涉及到了频繁的插入元素到list中的话,尽量还是不要用ArrayList,数组,定长数组,长度是固定的,元素大量的移动,数组的扩容+元素的拷贝。 \ No newline at end of file diff --git "a/docs/java\351\233\206\345\220\210/02-java\351\233\206\345\220\210\344\271\213LinkedList\346\272\220\347\240\201\345\211\226\346\236\220/02-java\351\233\206\345\220\210\344\271\213LinkedList\346\272\220\347\240\201\345\211\226\346\236\220.md" "b/docs/java\351\233\206\345\220\210/02-java\351\233\206\345\220\210\344\271\213LinkedList\346\272\220\347\240\201\345\211\226\346\236\220/02-java\351\233\206\345\220\210\344\271\213LinkedList\346\272\220\347\240\201\345\211\226\346\236\220.md" new file mode 100644 index 0000000000000000000000000000000000000000..bcae6c59a244d77125ec51d210c1768a81c80c57 --- /dev/null +++ "b/docs/java\351\233\206\345\220\210/02-java\351\233\206\345\220\210\344\271\213LinkedList\346\272\220\347\240\201\345\211\226\346\236\220/02-java\351\233\206\345\220\210\344\271\213LinkedList\346\272\220\347\240\201\345\211\226\346\236\220.md" @@ -0,0 +1,399 @@ +* #### 前言 +* #### 基本原理 +* #### 数据结构 + * ##### 双向链表(LinkedList所采用的数据结构) + * #### 常用方法源码剖析 + * ##### 插入元素 + * ###### add(),默认就是在队列的尾部插入一个元素,在那个双向链表的尾部插入一个元素 + * ###### addLast() 与add()方法是一样的,也是在尾部插入一个元素 + * ###### add(index, element),是在队列的中间插入一个元素 + * ###### addFirst(),在队列的头部插入一个元素 + * ##### 换取元素 + * ###### getFirst() == peek():获取头部的元素 + * ###### getLast(): 获取尾部的元素 + * ###### get(): 获取元素 + * ##### 删除元素 + * ###### removeLast():删除最后一个 + * ###### removeFirst() == poll():删除第一个 + * ###### remove(int index):删除指定的index + + * #### 总结 + * ##### 优点 + * ##### 缺点 + +* * * + +> ### `前言` + +#####     LinkedList 是我们日常开发中使用比较常见的一个集合,今儿我们通过源码来看看它底层是怎么来实现的,了解了解它的优缺点和真正适合的场景。 + +* * * +> ### `基本原理` + +#####     LinkedList的底层是基于`双向链表`来实现的。 + +* * * +> ### `数据结构` + + * #### `双向链表` + +``` +private static class Node { + E item; + Node next; + Node prev; + + Node(Node prev, E element, Node next) { + this.item = element; + this.next = next; + this.prev = prev; + } + } +``` + + #### 图解(假设这个链表中有三个元素[Node]): + ![99ca9d636f3fa6ee3f71c529fd4acedf](02-java集合之LinkedList源码剖析.resources/59-LinkedList 双向链表.png) + +* * * + +>#### `常用方法源码剖析` + +> ##### `插入元素` + * ##### ` add()`,默认就是在队列的尾部插入一个元素,在双向链表的尾部插入一个元素 + * ##### ` addLast() 与add()方法是一样的`,也是在双向链表的尾部插入一个元素 + +``` + /** + * Appends the specified element to the end of this list. + * + *

This method is equivalent to {@link #addLast}. + * + * @param e element to be appended to this list + * @return {@code true} (as specified by {@link Collection#add}) + * add(),默认就是在队列的尾部插入一个元素,在那个双向链表的尾部插入一个元素 + */ + public boolean add(E e) { + linkLast(e); + return true; + } + + /** + * Appends the specified element to the end of this list. + * + *

This method is equivalent to {@link #add}. + * + * @param e the element to add + * addLast() 与add()方法是一样的,也是在双向链表的尾部插入一个元素 + */ + public void addLast(E e) { + linkLast(e); + } + + + /** + * Links e as last element. + * 新加入的元素作为最后一个 + */ + void linkLast(E e) { + // 指针 l 指向 last + final Node l = last; + + // 新元素 e -> new 一个 Node => newNode + final Node newNode = new Node<>(l, e, null); + + // last指针指向newNode + last = newNode; + + //判断l是否为null + if (l == null) + // l为null,fist指向newNode + first = newNode; + else + // l 不为null, l的下一个元素指向 newNode + l.next = newNode; + + // linkedList大小+1 + size++; + modCount++; + } +``` +> #### 图解(假设这个链表中有三个元素[Node]): +![3ad55795325533e6b21f8b431ff1701e](02-java集合之LinkedList源码剖析.resources/59-LinkedList2.png) + + +*** + + * ##### `add(index, element) `,是在队列的中间插入一个元素 + +``` + /** + * Inserts the specified element at the specified position in this list. + * Shifts the element currently at that position (if any) and any + * subsequent elements to the right (adds one to their indices). + * + * @param index index at which the specified element is to be inserted + * @param element element to be inserted + * @throws IndexOutOfBoundsException {@inheritDoc} + */ + public void add(int index, E element) { + // 判断当前传入的index是否越界 + checkPositionIndex(index); + + if (index == size) + // 如果传入的index == 当前链表的大小 + // 就往双向链表的尾部插入一个元素 + linkLast(element); + else + // 如果传入的index != 当前链表的大小 + // 指定链表的位置的元素前边添加传入的元素 + // node(index) + // linkBefore(element, node(index)); + linkBefore(element, node(index)); + } + + // 判断当前传入的index是否越界 + private void checkPositionIndex(int index) { + if (!isPositionIndex(index)) + throw new IndexOutOfBoundsException(outOfBoundsMsg(index)); + } + + /** + * Returns the (non-null) Node at the specified element index. + * 经典链表遍历的代码 + */ + Node node(int index) { + // assert isElementIndex(index); + + // size >> 1 = size / 2 + + // 判断index 是在链表的前半部分还是后半部分 + if (index < (size >> 1)) { + // index在链表的前半部分 + Node x = first; + // 从队列的对头开始遍历 + for (int i = 0; i < index; i++) + x = x.next; + return x; + } else { + // index在链表的后半部分 + Node x = last; + // 从队列的队尾遍历 + for (int i = size - 1; i > index; i--) + x = x.prev; + return x; + } + } + + /** + * Inserts element e before non-null Node succ. + */ + void linkBefore(E e, Node succ) { + // assert succ != null; + final Node pred = succ.prev; + final Node newNode = new Node<>(pred, e, succ); + succ.prev = newNode; + if (pred == null) + first = newNode; + else + pred.next = newNode; + size++; + modCount++; + } + +``` + +> #### `Node node(int index)` 图解: +![ad74acc630c3125d67faff533c9d81f8](02-java集合之LinkedList源码剖析.resources/59-LinkedList add(e, index) (3).png) + + +#### size >> 1,比如说现在是size = 4,size >> 1相当于是size / 2,整除,得到的是2 +#### index < (size >> 1),如果index < (size / 2), +#### 已知 index = 1,要插入的位置,是在队列的前半部分,那么就会从队列头部开始遍历,找到index那个位置的Node, 也就是第二个Node元素 + +> #### 接下来就是 `void linkBefore(E e, Node succ)` : +![46a503a9fe1c0731a464b97ad8381b7b](02-java集合之LinkedList源码剖析.resources/59-LinkedList add(e, index)2.png) + +* * * +> ##### `换取元素` + * ##### ` getFirst() == peek() `:获取头部的元素 + * ##### `getLast()`: 获取尾部的元素 + * ##### `get()`: 获取元素 +``` + /** + * Returns the first element in this list. + * + * @return the first element in this list + * @throws NoSuchElementException if this list is empty + */ + public E getFirst() { + final Node f = first; + if (f == null) + throw new NoSuchElementException(); + return f.item; + } + + /** + * Retrieves, but does not remove, the head (first element) of this list. + * + * @return the head of this list, or {@code null} if this list is empty + * @since 1.5 + */ + public E peek() { + final Node f = first; + return (f == null) ? null : f.item; + } + + /** + * Returns the last element in this list. + * + * @return the last element in this list + * @throws NoSuchElementException if this list is empty + */ + public E getLast() { + final Node l = last; + if (l == null) + throw new NoSuchElementException(); + return l.item; + } + + /** + * Returns the element at the specified position in this list. + * + * @param index index of the element to return + * @return the element at the specified position in this list + * @throws IndexOutOfBoundsException {@inheritDoc} + */ + public E get(int index) { + checkElementIndex(index); + return node(index).item; + } + + // 上述文字已经写过如何遍历链表或者元素了 + node(index).item; +``` + +*** + +> ##### `删除元素` + * ##### `removeLast()`:删除最后一个 + * ##### `removeFirst() == poll()`:删除第一个 + * ##### `remove(int index)`:删除指定的index +``` + /** + * Removes and returns the last element from this list. + * + * @return the last element from this list + * @throws NoSuchElementException if this list is empty + */ + public E removeLast() { + final Node l = last; + if (l == null) + throw new NoSuchElementException(); + return unlinkLast(l); + } + + /** + * Removes and returns the first element from this list. + * + * @return the first element from this list + * @throws NoSuchElementException if this list is empty + */ + public E removeFirst() { + final Node f = first; + if (f == null) + throw new NoSuchElementException(); + return unlinkFirst(f); + } + + /** + * Retrieves and removes the head (first element) of this list. + * + * @return the head of this list, or {@code null} if this list is empty + * @since 1.5 + */ + public E poll() { + final Node f = first; + return (f == null) ? null : unlinkFirst(f); + } + + /** + * Retrieves and removes the head (first element) of this list. + * + * @return the head of this list + * @throws NoSuchElementException if this list is empty + * @since 1.5 + */ + public E remove() { + return removeFirst(); + } + + /** + * LInkedList 删除第一个元素 + * Unlinks non-null first node f. + */ + private E unlinkFirst(Node f) { + // assert f == first && f != null; + // 要删除的Node + final E element = f.item; + + //获取Node的下一个元素 + final Node next = f.next; + + // 当前Node设置为null + f.item = null; + + // 当前Node下一个指向为Null + f.next = null; // help GC + + // first指针指向next + first = next; + + //判断next指向的元素是否为null + if (next == null) + // 最后一个节点为null + last = null; + else + // next的上一个节点为null,此时next为链表第一个节点 + next.prev = null; + + //链表大小-1 + size--; + modCount++; + return element; + } + + /** + * LInkedList 删除最后一个元素 + * Unlinks non-null last node l. + */ + private E unlinkLast(Node l) { + // assert l == last && l != null; + final E element = l.item; + final Node prev = l.prev; + l.item = null; + l.prev = null; // help GC + last = prev; + if (prev == null) + first = null; + else + prev.next = null; + size--; + modCount++; + return element; + } +``` + +> #### ` unlinkFirst(Node f)` (这里以LinkedList 删除第一个元素为例)图解: +![118958a4bebe8bc573df02b9bad18b78](02-java集合之LinkedList源码剖析.resources/59-LinkedList unlinkFirst.png) + +*** + +> ### `总结` + + * #### ` 优点` + * #### 基于于链表来实现的,非常适合各种元素频繁的插入链表里面去 ,所以不会出现任何的大量元素的挪动,也不会出现说数组的扩容,适合做队列;(队中插入数据的时候没有队头和队尾性能那么好,因为要走一个遍历到指定位置) + + + * #### `缺点 ` + * #### 如果是要随机位置获取一个元素,gett(int index)这个方法,会导致需要遍历,如果里面的数据很多的话,遍历的性能还是比较差的,才能获取到一个随机位置的元素. + \ No newline at end of file diff --git "a/docs/java\351\233\206\345\220\210/02-java\351\233\206\345\220\210\344\271\213LinkedList\346\272\220\347\240\201\345\211\226\346\236\220/02-java\351\233\206\345\220\210\344\271\213LinkedList\346\272\220\347\240\201\345\211\226\346\236\220.resources/59-LinkedList add (1).png" "b/docs/java\351\233\206\345\220\210/02-java\351\233\206\345\220\210\344\271\213LinkedList\346\272\220\347\240\201\345\211\226\346\236\220/02-java\351\233\206\345\220\210\344\271\213LinkedList\346\272\220\347\240\201\345\211\226\346\236\220.resources/59-LinkedList add (1).png" new file mode 100644 index 0000000000000000000000000000000000000000..4cb9427ff42d3a4a4a0698c2341743a5a5336b71 Binary files /dev/null and "b/docs/java\351\233\206\345\220\210/02-java\351\233\206\345\220\210\344\271\213LinkedList\346\272\220\347\240\201\345\211\226\346\236\220/02-java\351\233\206\345\220\210\344\271\213LinkedList\346\272\220\347\240\201\345\211\226\346\236\220.resources/59-LinkedList add (1).png" differ diff --git "a/docs/java\351\233\206\345\220\210/02-java\351\233\206\345\220\210\344\271\213LinkedList\346\272\220\347\240\201\345\211\226\346\236\220/02-java\351\233\206\345\220\210\344\271\213LinkedList\346\272\220\347\240\201\345\211\226\346\236\220.resources/59-LinkedList add(e, index) (1).png" "b/docs/java\351\233\206\345\220\210/02-java\351\233\206\345\220\210\344\271\213LinkedList\346\272\220\347\240\201\345\211\226\346\236\220/02-java\351\233\206\345\220\210\344\271\213LinkedList\346\272\220\347\240\201\345\211\226\346\236\220.resources/59-LinkedList add(e, index) (1).png" new file mode 100644 index 0000000000000000000000000000000000000000..d94f2321b7dfa73aef79d529b699c9acfef160fe Binary files /dev/null and "b/docs/java\351\233\206\345\220\210/02-java\351\233\206\345\220\210\344\271\213LinkedList\346\272\220\347\240\201\345\211\226\346\236\220/02-java\351\233\206\345\220\210\344\271\213LinkedList\346\272\220\347\240\201\345\211\226\346\236\220.resources/59-LinkedList add(e, index) (1).png" differ diff --git "a/docs/java\351\233\206\345\220\210/02-java\351\233\206\345\220\210\344\271\213LinkedList\346\272\220\347\240\201\345\211\226\346\236\220/02-java\351\233\206\345\220\210\344\271\213LinkedList\346\272\220\347\240\201\345\211\226\346\236\220.resources/59-LinkedList add(e, index) (2).png" "b/docs/java\351\233\206\345\220\210/02-java\351\233\206\345\220\210\344\271\213LinkedList\346\272\220\347\240\201\345\211\226\346\236\220/02-java\351\233\206\345\220\210\344\271\213LinkedList\346\272\220\347\240\201\345\211\226\346\236\220.resources/59-LinkedList add(e, index) (2).png" new file mode 100644 index 0000000000000000000000000000000000000000..168980aba568ad598996493d24168c05a506d830 Binary files /dev/null and "b/docs/java\351\233\206\345\220\210/02-java\351\233\206\345\220\210\344\271\213LinkedList\346\272\220\347\240\201\345\211\226\346\236\220/02-java\351\233\206\345\220\210\344\271\213LinkedList\346\272\220\347\240\201\345\211\226\346\236\220.resources/59-LinkedList add(e, index) (2).png" differ diff --git "a/docs/java\351\233\206\345\220\210/02-java\351\233\206\345\220\210\344\271\213LinkedList\346\272\220\347\240\201\345\211\226\346\236\220/02-java\351\233\206\345\220\210\344\271\213LinkedList\346\272\220\347\240\201\345\211\226\346\236\220.resources/59-LinkedList add(e, index) (3).png" "b/docs/java\351\233\206\345\220\210/02-java\351\233\206\345\220\210\344\271\213LinkedList\346\272\220\347\240\201\345\211\226\346\236\220/02-java\351\233\206\345\220\210\344\271\213LinkedList\346\272\220\347\240\201\345\211\226\346\236\220.resources/59-LinkedList add(e, index) (3).png" new file mode 100644 index 0000000000000000000000000000000000000000..96d4bf4d8664569db3bae28cb50154d631d0789b Binary files /dev/null and "b/docs/java\351\233\206\345\220\210/02-java\351\233\206\345\220\210\344\271\213LinkedList\346\272\220\347\240\201\345\211\226\346\236\220/02-java\351\233\206\345\220\210\344\271\213LinkedList\346\272\220\347\240\201\345\211\226\346\236\220.resources/59-LinkedList add(e, index) (3).png" differ diff --git "a/docs/java\351\233\206\345\220\210/02-java\351\233\206\345\220\210\344\271\213LinkedList\346\272\220\347\240\201\345\211\226\346\236\220/02-java\351\233\206\345\220\210\344\271\213LinkedList\346\272\220\347\240\201\345\211\226\346\236\220.resources/59-LinkedList add(e, index).png" "b/docs/java\351\233\206\345\220\210/02-java\351\233\206\345\220\210\344\271\213LinkedList\346\272\220\347\240\201\345\211\226\346\236\220/02-java\351\233\206\345\220\210\344\271\213LinkedList\346\272\220\347\240\201\345\211\226\346\236\220.resources/59-LinkedList add(e, index).png" new file mode 100644 index 0000000000000000000000000000000000000000..46639eb80ff031a1cd528f4b852994d77dd0637f Binary files /dev/null and "b/docs/java\351\233\206\345\220\210/02-java\351\233\206\345\220\210\344\271\213LinkedList\346\272\220\347\240\201\345\211\226\346\236\220/02-java\351\233\206\345\220\210\344\271\213LinkedList\346\272\220\347\240\201\345\211\226\346\236\220.resources/59-LinkedList add(e, index).png" differ diff --git "a/docs/java\351\233\206\345\220\210/02-java\351\233\206\345\220\210\344\271\213LinkedList\346\272\220\347\240\201\345\211\226\346\236\220/02-java\351\233\206\345\220\210\344\271\213LinkedList\346\272\220\347\240\201\345\211\226\346\236\220.resources/59-LinkedList add(e, index)2.png" "b/docs/java\351\233\206\345\220\210/02-java\351\233\206\345\220\210\344\271\213LinkedList\346\272\220\347\240\201\345\211\226\346\236\220/02-java\351\233\206\345\220\210\344\271\213LinkedList\346\272\220\347\240\201\345\211\226\346\236\220.resources/59-LinkedList add(e, index)2.png" new file mode 100644 index 0000000000000000000000000000000000000000..6c68b501af1245173b6014ee6541d88f600c9c37 Binary files /dev/null and "b/docs/java\351\233\206\345\220\210/02-java\351\233\206\345\220\210\344\271\213LinkedList\346\272\220\347\240\201\345\211\226\346\236\220/02-java\351\233\206\345\220\210\344\271\213LinkedList\346\272\220\347\240\201\345\211\226\346\236\220.resources/59-LinkedList add(e, index)2.png" differ diff --git "a/docs/java\351\233\206\345\220\210/02-java\351\233\206\345\220\210\344\271\213LinkedList\346\272\220\347\240\201\345\211\226\346\236\220/02-java\351\233\206\345\220\210\344\271\213LinkedList\346\272\220\347\240\201\345\211\226\346\236\220.resources/59-LinkedList unlinkFirst.png" "b/docs/java\351\233\206\345\220\210/02-java\351\233\206\345\220\210\344\271\213LinkedList\346\272\220\347\240\201\345\211\226\346\236\220/02-java\351\233\206\345\220\210\344\271\213LinkedList\346\272\220\347\240\201\345\211\226\346\236\220.resources/59-LinkedList unlinkFirst.png" new file mode 100644 index 0000000000000000000000000000000000000000..50b455d04f04fa9264a832eee4e67afe83f547e6 Binary files /dev/null and "b/docs/java\351\233\206\345\220\210/02-java\351\233\206\345\220\210\344\271\213LinkedList\346\272\220\347\240\201\345\211\226\346\236\220/02-java\351\233\206\345\220\210\344\271\213LinkedList\346\272\220\347\240\201\345\211\226\346\236\220.resources/59-LinkedList unlinkFirst.png" differ diff --git "a/docs/java\351\233\206\345\220\210/02-java\351\233\206\345\220\210\344\271\213LinkedList\346\272\220\347\240\201\345\211\226\346\236\220/02-java\351\233\206\345\220\210\344\271\213LinkedList\346\272\220\347\240\201\345\211\226\346\236\220.resources/59-LinkedList \345\217\214\345\220\221\351\223\276\350\241\250.png" "b/docs/java\351\233\206\345\220\210/02-java\351\233\206\345\220\210\344\271\213LinkedList\346\272\220\347\240\201\345\211\226\346\236\220/02-java\351\233\206\345\220\210\344\271\213LinkedList\346\272\220\347\240\201\345\211\226\346\236\220.resources/59-LinkedList \345\217\214\345\220\221\351\223\276\350\241\250.png" new file mode 100644 index 0000000000000000000000000000000000000000..15df25020543f017fe44a5a77b613abb40bdc669 Binary files /dev/null and "b/docs/java\351\233\206\345\220\210/02-java\351\233\206\345\220\210\344\271\213LinkedList\346\272\220\347\240\201\345\211\226\346\236\220/02-java\351\233\206\345\220\210\344\271\213LinkedList\346\272\220\347\240\201\345\211\226\346\236\220.resources/59-LinkedList \345\217\214\345\220\221\351\223\276\350\241\250.png" differ diff --git "a/docs/java\351\233\206\345\220\210/02-java\351\233\206\345\220\210\344\271\213LinkedList\346\272\220\347\240\201\345\211\226\346\236\220/02-java\351\233\206\345\220\210\344\271\213LinkedList\346\272\220\347\240\201\345\211\226\346\236\220.resources/59-LinkedList \345\217\214\345\220\221\351\223\276\350\241\250_1.png" "b/docs/java\351\233\206\345\220\210/02-java\351\233\206\345\220\210\344\271\213LinkedList\346\272\220\347\240\201\345\211\226\346\236\220/02-java\351\233\206\345\220\210\344\271\213LinkedList\346\272\220\347\240\201\345\211\226\346\236\220.resources/59-LinkedList \345\217\214\345\220\221\351\223\276\350\241\250_1.png" new file mode 100644 index 0000000000000000000000000000000000000000..744cb9e55d4e9691665171862537287b98e707b5 Binary files /dev/null and "b/docs/java\351\233\206\345\220\210/02-java\351\233\206\345\220\210\344\271\213LinkedList\346\272\220\347\240\201\345\211\226\346\236\220/02-java\351\233\206\345\220\210\344\271\213LinkedList\346\272\220\347\240\201\345\211\226\346\236\220.resources/59-LinkedList \345\217\214\345\220\221\351\223\276\350\241\250_1.png" differ diff --git "a/docs/java\351\233\206\345\220\210/02-java\351\233\206\345\220\210\344\271\213LinkedList\346\272\220\347\240\201\345\211\226\346\236\220/02-java\351\233\206\345\220\210\344\271\213LinkedList\346\272\220\347\240\201\345\211\226\346\236\220.resources/59-LinkedList \345\217\214\345\220\221\351\223\276\350\241\250_2.png" "b/docs/java\351\233\206\345\220\210/02-java\351\233\206\345\220\210\344\271\213LinkedList\346\272\220\347\240\201\345\211\226\346\236\220/02-java\351\233\206\345\220\210\344\271\213LinkedList\346\272\220\347\240\201\345\211\226\346\236\220.resources/59-LinkedList \345\217\214\345\220\221\351\223\276\350\241\250_2.png" new file mode 100644 index 0000000000000000000000000000000000000000..a580ae027d83568953fc9e3cbfa07d8d8f2744f1 Binary files /dev/null and "b/docs/java\351\233\206\345\220\210/02-java\351\233\206\345\220\210\344\271\213LinkedList\346\272\220\347\240\201\345\211\226\346\236\220/02-java\351\233\206\345\220\210\344\271\213LinkedList\346\272\220\347\240\201\345\211\226\346\236\220.resources/59-LinkedList \345\217\214\345\220\221\351\223\276\350\241\250_2.png" differ diff --git "a/docs/java\351\233\206\345\220\210/02-java\351\233\206\345\220\210\344\271\213LinkedList\346\272\220\347\240\201\345\211\226\346\236\220/02-java\351\233\206\345\220\210\344\271\213LinkedList\346\272\220\347\240\201\345\211\226\346\236\220.resources/59-LinkedList \345\217\214\345\220\221\351\223\276\350\241\250_3.png" "b/docs/java\351\233\206\345\220\210/02-java\351\233\206\345\220\210\344\271\213LinkedList\346\272\220\347\240\201\345\211\226\346\236\220/02-java\351\233\206\345\220\210\344\271\213LinkedList\346\272\220\347\240\201\345\211\226\346\236\220.resources/59-LinkedList \345\217\214\345\220\221\351\223\276\350\241\250_3.png" new file mode 100644 index 0000000000000000000000000000000000000000..76ccd01851d111412a6c31a650513e169f3ad89b Binary files /dev/null and "b/docs/java\351\233\206\345\220\210/02-java\351\233\206\345\220\210\344\271\213LinkedList\346\272\220\347\240\201\345\211\226\346\236\220/02-java\351\233\206\345\220\210\344\271\213LinkedList\346\272\220\347\240\201\345\211\226\346\236\220.resources/59-LinkedList \345\217\214\345\220\221\351\223\276\350\241\250_3.png" differ diff --git "a/docs/java\351\233\206\345\220\210/02-java\351\233\206\345\220\210\344\271\213LinkedList\346\272\220\347\240\201\345\211\226\346\236\220/02-java\351\233\206\345\220\210\344\271\213LinkedList\346\272\220\347\240\201\345\211\226\346\236\220.resources/59-LinkedList2.png" "b/docs/java\351\233\206\345\220\210/02-java\351\233\206\345\220\210\344\271\213LinkedList\346\272\220\347\240\201\345\211\226\346\236\220/02-java\351\233\206\345\220\210\344\271\213LinkedList\346\272\220\347\240\201\345\211\226\346\236\220.resources/59-LinkedList2.png" new file mode 100644 index 0000000000000000000000000000000000000000..04d6eb9b49865bfe57a107572e7875a2a32c5b7c Binary files /dev/null and "b/docs/java\351\233\206\345\220\210/02-java\351\233\206\345\220\210\344\271\213LinkedList\346\272\220\347\240\201\345\211\226\346\236\220/02-java\351\233\206\345\220\210\344\271\213LinkedList\346\272\220\347\240\201\345\211\226\346\236\220.resources/59-LinkedList2.png" differ