ArrayList和LinkList源码分析

一、ArrayList

1.1 ArrayList简介

ArrayList就是动态数组,它的容量可以动态增长和缩减。

public class ArrayList<E> extends AbstractList<E>
        implements List<E>, RandomAccess, Cloneable, java.io.Serializable

 extends AbstractList :ArrayList 继承了AbstractList类,使用其中的一些通用的方法,也可以自己实现特有的方法。

    implements List<E>, RandomAccess, Cloneable, java.io.SerializableRandomAccess, Cloneable, java.io.Serializable:实现了这些接口, List, RandomAccess, Cloneable, java.io.SerializableRandomAccess, Cloneable, java.io.Serializable

1.2 主要方法

1.2.1 add()方法

add的方法有两个,传入一个参数和传入两个参数的。

  • public boolean add(E e)    //直接将指定元素e追加到列表末尾

  • public void add(int index, E element)   //将指定元素插入到列表中的指定位置。

ArrayList<Long> arrayList = new ArrayList();

public ArrayList() {
        this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
    }
Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {}; //初始化成一个空数组

 (1)public boolean add(E e) 

public boolean add(E e) {
        modCount++;
  //elementData初始化为空数组,size最开始默认为0
  add(e, elementData, size);
      return true; 
}

private void add(E e, Object[] elementData, int s) {
     // 判断是否需要扩容
    if (s == elementData.length)
    // 扩容操作 将原来的数组的长度变为数组长度的1.5倍 length + (length >> 1)
        elementData = grow();
    elementData[s] = e;//将元素放入到List末尾
   size = s + 1;
}
private Object[] grow() {
    return grow(mincapacit:size + 1);
}
//扩容,保证ArrayList至少能存储minCapacity个元素 
private Object[] grow(int minCapacity) {
  // 获取当前数组的容量
    int oldCapacity = elementData.length;
  // 扩容。新的容量=当前容量+当前容量/2.即将当前容量增加一半(当前容量增加1.5倍)。 
    if (oldCapacity > 0 || elementData != DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
        int newCapacity = ArraysSupport.newLength(oldCapacity,
                minCapacity - oldCapacity, /* minimum growth */
                oldCapacity >> 1           /* preferred growth */);
    //新的容量大小已经确定好了,就copy数组,改变容量大小。 
    //copyof(原数组,新的数组长度)
        return elementData = Arrays.copyOf(elementData, newCapacity);
    } else {
        return elementData = new Object[Math.max(DEFAULT_CAPACITY, minCapacity)];//DEFAULT_CAPACITY = 10;
   }
}

public static int newLength(int oldLength, int minGrowth, int prefGrowth) {
    // assert oldLength >= 0
    // assert minGrowth > 0

    int newLength = Math.max(minGrowth, prefGrowth) + oldLength;
    //传入的容量是不是小于最大容量返回传入的容量,否则返回最大容量判断
    if (newLength - MAX_ARRAY_LENGTH <= 0) {
        return newLength;
    }
    return hugeLength(oldLength, minGrowth);
}


private static int hugeLength(int oldLength, int minGrowth) {
    int minLength = oldLength + minGrowth;
    if (minLength < 0) { // overflow
        throw new OutOfMemoryError("Required array length too large");
    }
  //如果传入的容量值小于等于最大容量值返回最大的Integer值2^31次方
    if (minLength <= MAX_ARRAY_LENGTH) {
        return MAX_ARRAY_LENGTH;
    }
    return Integer.MAX_VALUE;
}

(2) public void add(int index, E element)  //删除指定索引处的元素:

public void add(int index, E element) {   
 
//越界检查if (index > size || index < 0)
        rangeCheckForAdd(index);
        modCount++;
        final int s;
        Object[] elementData;
     //判断数组长度与集合size是否相等 if ((s = size) == (elementData = this.elementData).length)
       //相等的话扩容 elementData = grow();
     //将原数组索引处(包括索引)后的元素拷贝到新数组中,放到从index+1位置开始 System.arraycopy(elementData, index, elementData, index + 1, s - index);
     //向索引处添加元素 elementData[index] = element; size = s + 1; }

1.2.2 remove()方法

(1public E remove(int index) //删除指定元素:

public E remove(int index) {
     //判断传入索引是否合法 Objects.checkIndex(index, size); final Object[] es = elementData;     //通过索引直接找到该元素 E oldValue = (E) es[index]; fastRemove(es, index); return oldValue; }

//专用的remove方法,跳过边界检查,并且不返回删除的值。
private void fastRemove(Object[] es, int i) {
    modCount++;
    final int newSize;
  //数组大小-1,并判断i是否在数组范围内
    if ((newSize = size - 1) > i)
     //将索引+1到数组结尾的元素复制到索引处到数组结尾
        System.arraycopy(es, i + 1, es, i, newSize - i);
  //因为并未变化数组容量,所以将后面未存放的置为空
    es[size = newSize] = null;
}

(2)public boolean remove(Object o)

public boolean remove(Object o) {
        final Object[] es = elementData;
        final int size = this.size;
        int i = 0;
// 这个是很早就有的一个 java 特性,可以命名一个语句块然后通过break name的方式跳出该语句块 found: { if (o == null) {
          //遍历数组找到null元素的索引 for (; i < size; i++) if (es[i] == null) break found; } else {
    //遍历数组找到o元素的索引 for (; i < size; i++) if (o.equals(es[i])) break found; } return false; }
     //将索引位置删除 fastRemove(es, i); return true; }

  

1.2.3 clear()方法

 public void clear() {
        modCount++;
        final Object[] es = elementData;
        for (int to = size, i = size = 0; i < to; i++)
            es[i] = null;
    }

1.2.4 addAll()方法

(1)public boolean addAll(Collection<? extends E> c)

public boolean addAll(Collection<? extends E> c) {
     //将集合转为数组 Object[] a = c.toArray(); modCount++; int numNew = a.length; if (numNew == 0) return false; Object[] elementData; final int s; if (numNew > (elementData = this.elementData).length - (s = size))
        //扩容 elementData = grow(s + numNew); System.arraycopy(a, 0, elementData, s, numNew);
     //集合个数增加 size = s + numNew; return true; }

(2)public boolean addAll(int index, Collection<? extends E> c) 

public boolean addAll(int index, Collection<? extends E> c) {
    //检查索引是否合法
    rangeCheckForAdd(index);
    //集合转为数组
    Object[] a = c.toArray();
    modCount++;
    int numNew = a.length;
    if (numNew == 0)
        return false;
    Object[] elementData;
    final int s;
    if (numNew > (elementData = this.elementData).length - (s = size))
        elementData = grow(s + numNew);
    //将要复制到的索引位置到数组结尾的元素复制到当前位置+要复制的数组长度
    int numMoved = s - index;
    if (numMoved > 0)
        System.arraycopy(elementData, index,
                         elementData, index + numNew,
                         numMoved);
    //将要复制的数组复制到指定的索引处
    System.arraycopy(a, 0, elementData, index, numNew);
    //集合个数增加
    size = s + numNew;
    return true;
}

1.2.5 get()方法

 public E get(int index) {
        Objects.checkIndex(index, size);
        return elementData(index);
    }

1.2.6 contains()方法

//是否包含某个元素

public boolean contains(Object o) {
        return indexOf(o) >= 0;
    }

  


//查找元素索引
public int indexOf(Object o) {
    return indexOfRange(o, 0, size);
}

int indexOfRange(Object o, int start, int end) {
    Object[] es = elementData;
  //如果传入的元素是空的判断
    if (o == null) {
        for (int i = start; i < end; i++) {
            if (es[i] == null) {
                return i;
            }
        }
    } else {
    //遍历查找值相同的元素
        for (int i = start; i < end; i++) {
            if (o.equals(es[i])) {
                return i;
            }
        }
    }
    return -1;
}

二、LinkedList

2.1 LinkedList简介

LinkedList是一个双链表,在添加和删除元素时具有比ArrayList更好的性能。但在get与set方面弱于ArrayList。

public class LinkedList<E>
    extends AbstractSequentialList<E>
    implements List<E>, Deque<E>, Cloneable, java.io.Serializable
  • extends AbstractSequentialList<E>

  • AbstractSequentialList 只支持按次序访问,这也是LinkedList随机访问效率低的原因之一。

2.2 主要方法

2.2.1 add()方法

add方法有两个

  • public boolean add(E e)  //将指定元素插入到链表的最后

  • public void add(int index, E element)   //在指定位置添加元素

(1)public boolean add(E e) 

//将指定元素插入到链表的最后
public boolean add(E e) { linkLast(e); return true; }
void linkLast(E e) {
    final Node<E> l = last;
  //新建节点newNode,节点的前指针指向l,后指针指向null
    final Node<E> newNode = new Node<>(l, e, null);
   //更新尾节点
    last = newNode;
    //如果原来的尾节点是null,则要更新头指针,如果不是则将原来的尾节点的后置指针指向newNode
    if (l == null)
        first = newNode;
    else
        l.next = newNode;
    size++;
    modCount++;
}

(2)public void add(int index, E element)

//在指定位置添加元素
public void add(int index, E element) {
      //检查索引是否合理
        checkPositionIndex(index);
        if (index == size)
            linkLast(element);
        else
            linkBefore(element, node(index));
    }

//取出对应index上的Node元素
Node<E> node(int index) {
    // assert isElementIndex(index);
  //"<<":*2的几次方 “>>”:/2的几次方,例如:size<<1:size*2的1次方
  //if判断index<size/2
    if (index < (size >> 1)) {
        Node<E> x = first;
    //从头部开始移动
        for (int i = 0; i < index; i++)
            x = x.next;
        return x;
    } else {
        Node<E> x = last;
     //从尾部开始移动
        for (int i = size - 1; i > index; i--)
            x = x.prev;
        return x;
    }
}

//在非空节点成功之前插入元素e
void linkBefore(E e, Node<E> succ) {
    // assert succ != null;
    final Node<E> pred = succ.prev;
  //创建新的节点 前驱节点为succ的前驱节点,后续节点为succ,则e元素就是插入在succ之前的
    final Node<E> newNode = new Node<>(pred, e, succ);
  //构建双向链表,succ的前驱节点为newNode
    succ.prev = newNode;
  //如果前驱节点为空则first为新节点
    if (pred == null)
        first = newNode;
    else
     //构建双向链表
        pred.next = newNode;
    size++;
    modCount++;
}

2.2.2 addAll()方法

//将集合插入到index之前

public boolean addAll(int index, Collection<? extends E> c) {
        checkPositionIndex(index);
     // 集合转数组
        Object[] a = c.toArray();
        int numNew = a.length;
        if (numNew == 0)
            return false;
        Node<E> pred, succ;
        if (index == size) {
        //succ的前驱节点直接赋值为最后节点,succ赋值为null,因为index在链表最后
            succ = null;
            pred = last;
        } else {
       //取出index上的节点
            succ = node(index);
            pred = succ.prev;
        }
     //遍历插入集合
        for (Object o : a) {
            @SuppressWarnings("unchecked") E e = (E) o;
            Node<E> newNode = new Node<>(pred, e, null);
            if (pred == null)
                first = newNode;
            else
                pred.next = newNode;
       //将前驱节点移动到新结点上,继续循环
            pred = newNode;
        }
     //pred已经走到最后
        if (succ == null) {
            last = pred;
        } else {
            pred.next = succ;
            succ.prev = pred;
        }
        size += numNew;
        modCount++;
        return true;
    }

 

2.2.3 clear()方法

 //请空链表
public void clear() {      //for循环,逐条置空 for (Node<E> x = first; x != null; ) { Node<E> next = x.next; x.item = null; x.next = null; x.prev = null; x = next; } first = last = null; size = 0; modCount++; }

2.2.4 remove()方法

public E remove(int index) {
        checkElementIndex(index);
        return unlink(node(index));
    }


E unlink(Node<E> x) {
    // assert x != null;
    final E element = x.item;
    final Node<E> next = x.next;
    final Node<E> prev = x.prev;
   //如果prev=null则删除的是头节点
    if (prev == null) {
        first = next;
    } else {
        prev.next = next;
    //置空删除节点的前置节点
        x.prev = null;
    }

    if (next == null) {
        last = prev;
    } else {
        next.prev = prev;
        x.next = null;
    }
  //置空删除的指定节点的值
    x.item = null;
    size--;
    modCount++;
    return element;
}

 2.2.5 get()方法

    public E get(int index) {
        checkElementIndex(index);
        return node(index).item;
    }

2.2.6 set()方法

//改
public E set(int index, E element) {
  //检查索引是否合法
  checkElementIndex(index);
  Node<E> x = node(index);
  //获取指定索引节点的值
  E oldVal = x.item;
  //将节点元素设置为新的值
  x.item = element;
  return oldVal;
}

2.2.7 indexof()方法

public int indexOf(Object o) {
        int index = 0;
        if (o == null) {
            for (Node<E> x = first; x != null; x = x.next) {
                if (x.item == null)
                    return index;
                index++;
            }
        } else {
            for (Node<E> x = first; x != null; x = x.next) {
                if (o.equals(x.item))
                    return index;
                index++;
            }
        }
        return -1;
    }

 

posted @ 2021-02-08 22:30  zq231  阅读(86)  评论(0)    收藏  举报