java jdk8 源码解析之util包:list集合类源码分析

list集合作为一个有序的集合,能够使用户很好的掌握元素在列表中的位置,通过整数的索引就可以从列表中获取想要的数据。

1.Collection

    collection类是集合中就基本的接口,一个集合代表这一组对象,有些集合是有序的有些是无序的,jdk没有提供任何来自Collection接口的直接实现,它提供的是更多的子接口的实现例如list和set,所以这个接口是为了保证集合最大的通用性为目的设置的,他的方法名主要有:

int size();

boolean isEmpty();

boolean contains(Object o);

Iterator<E> iterator();

Object[] toArray();  //返回数组

boolean add(E e);

boolean remove(Object o);

 2.ArrayList

    是一个可调整大小的数组,继承List(Collection子接口)接口,实现了大部分的list操作,可插入所有类型元素以及重复值,包括null值。除了基本操作之外,还提供了很多控制内部数组大小的方法,非线程同步。类继承如下:

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

  transient Object[] elementData;   //存放元素的Object数组

  ...
}

add方法

 public boolean add(E e) {
        ensureCapacityInternal(size + 1);  // 完成扩容功能
        elementData[size++] = e;
        return true;
    }

我们主要分析扩容方法:

  private void ensureCapacityInternal(int minCapacity) {
        if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {  //如果表为第一次创建,则初始化容器长度
            minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
        }

        ensureExplicitCapacity(minCapacity);   
    }
 private void ensureExplicitCapacity(int minCapacity) {
        modCount++;  //记录操作

        // 如果最小容量大于容器长度则需要对数组进行扩充
        if (minCapacity - elementData.length > 0)
            grow(minCapacity);
    }
  private void grow(int minCapacity) {
        // overflow-conscious code
        int oldCapacity = elementData.length;
        int newCapacity = oldCapacity + (oldCapacity >> 1); //扩充1/2
        if (newCapacity - minCapacity < 0)
            newCapacity = minCapacity;
        if (newCapacity - MAX_ARRAY_SIZE > 0)  //如果扩充超过最大可扩充长度(最大为int的最大值)则重新取值
            newCapacity = hugeCapacity(minCapacity);
        // minCapacity is usually close to size, so this is a win:
        elementData = Arrays.copyOf(elementData, newCapacity); //创建一个新的数组
    }

remove方法

public boolean remove(Object o) {
        if (o == null) {  //如果存的是空值
            for (int index = 0; index < size; index++)  
                if (elementData[index] == null) {
                    fastRemove(index);
                    return true;
                }
        } else {
            for (int index = 0; index < size; index++)
                if (o.equals(elementData[index])) {  //调用equals判断是否相等
                    fastRemove(index);
                    return true;
                }
        }
        return false;
    }

    /*
     * Private remove method that skips bounds checking and does not
     * return the value removed.
     */
    private void fastRemove(int index) {
        modCount++;
        int numMoved = size - index - 1;  //需要移动的元素数量
        if (numMoved > 0)
            System.arraycopy(elementData, index+1, elementData, index, 
                             numMoved);  //调用arraycopy覆盖需要删除的值
        elementData[--size] = null; // clear to let GC do its work
    }

 get 方法

   public E get(int index) {
        rangeCheck(index);  //判断index是否超出范围

        return elementData(index);
    }

  E elementData(int index) {
        return (E) elementData[index]; //通过下标获取元素
    }

     根据源码可知添加操作比删除操作在时间复杂度上更小,添加是O(1),删除是O(n),容器的扩容和删除元素是调用copyof和arrycopy方法的,底层实现的是c++,所以效率会更高。容器的容积是有限的,最大值为int类型的最大值。

2.LinkList

      属于双链表结构,继承List和Deque接口,允许插入任何值以及重复值,包括空值。

public class LinkedList<E>
    extends AbstractSequentialList<E>
    implements List<E>, Deque<E>, Cloneable, java.io.Serializable
{
    transient int size = 0;  //容量

    transient Node<E> first;  //链表第一个元素

    transient Node<E> last;  //链表最后一个元素


    private static class Node<E> {
        E item;
        Node<E> next; //下一个元素
        Node<E> prev;  //上一个元素

        Node(Node<E> prev, E element, Node<E> next) {
            this.item = element;
            this.next = next;
            this.prev = prev;
        }
    }


....
}

Deque:定义了双链表的操作方法,提高子类的通用性

AbstractSequentialList:此抽象类提供了框架的实现以减小实现此接口的工作量,适用于顺序存储列表的实现。

add方法

public boolean add(E e) {
        linkLast(e);  //插入尾部连接
        return true;
    }

 void linkLast(E e) {
        final Node<E> l = last;
        final Node<E> newNode = new Node<>(l, e, null);
        last = newNode;
        if (l == null) //如果第一次插入
            first = newNode;
        else
            l.next = newNode;
        size++;
        modCount++;
    }

remove方法

 public boolean remove(Object o) {
        if (o == null) {  
            for (Node<E> x = first; x != null; x = x.next) {
                if (x.item == null) {
                    unlink(x);
                    return true;
                }
            }
        } else {
            for (Node<E> x = first; x != null; x = x.next) {
                if (o.equals(x.item)) {
                    unlink(x);
                    return true;
                }
            }
        }
        return false;
    }

 E unlink(Node<E> x) { //x需要删除的元素
        // assert x != null;
        final E element = x.item;
        final Node<E> next = x.next;
        final Node<E> prev = x.prev;

        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;
    }

 get方法

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

 Node<E> node(int index) {
        // assert isElementIndex(index);

        if (index < (size >> 1)) {  //判断index是否是数组长度的前段
            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;
        }
    }

linklist类,内部是一个双向链表结构。链表内的每个node对象保存了前后元素的引用。我们可以向链表两端进行插入删除的操作,除此之外他不会受到容量的限制,数组元素可以有无限多个(与虚拟机配置有关);查询方面需要通过从头或者尾开始遍历相对线性表来说效率会低些。

3.Vector

同步版本的ArrayList类,与ArrayList实现原理相差无几。唯一区别就是Vector是线程安全的。主要的add方法如下:

 public synchronized boolean add(E e) {
        modCount++;
        ensureCapacityHelper(elementCount + 1);  //确保容器容量足够
        elementData[elementCount++] = e;
        return true;
    }

以上就是我对list集合的理解。

猜你喜欢

转载自blog.csdn.net/mxy88888/article/details/91477802