Java基础-List集合源码(ArrayList、LinkedList)

List集合

ArrayList(数组集合)

private static final int DEFAULT_CAPACITY = 10;//添加第一个元素时默认到10的大小
private static final Object[] EMPTY_ELEMENTDATA = {};//创建指定大小为0时返回该空数组
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};//不指定大小默认返回
transient Object[] elementData;//保存要添加的元素,当第一次添加时扩容到DEFAULT_CAPACITY 
private int size;//实际lisk中集合的元素个数

构造函数

 	//当用户指定大小时调用
 	public ArrayList(int initialCapacity) {
 		//指定大小>0时创建大小相等的数组
        if (initialCapacity > 0) {
            this.elementData = new Object[initialCapacity];
        } else if (initialCapacity == 0) {
      		//指定大小==0时调用EMPTY_ELEMENTDATA
            this.elementData = EMPTY_ELEMENTDATA;
        } else {
        	//<0抛出异常
            throw new IllegalArgumentException("Illegal Capacity: "+
                                               initialCapacity);
        }
    }
    
	//不指定大小时调用
 	public ArrayList() {
        this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
    }
	

注:底层由数组实现,存储的元素长度可变,查询效率高,增删效率低,线程不安全。使用频率很高

  • 创建时: 通过无参构造方法的方式ArrayList()初始化,则赋值底层数Object[] elementData为一个默认空数组Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {}所以数组容量为0,只有真正对数据进行添加add时,才分配默认DEFAULT_CAPACITY = 10的初始容量
  • 添加时:先检查当前容量是否需要扩容,如果需要扩容的话,扩容为原数组大小的1.5倍,新创建一个数组把原数据和新添加的数组copy到新数组中。

add(E e)

	public boolean add(E e) {
		//确认list容量,尝试容量加1,看看有无必要
        ensureCapacityInternal(size + 1);  
        //添加元素
        elementData[size++] = e;
        return true;
    }

	//确定容量,是否需要扩容
	private void ensureCapacityInternal(int minCapacity) {
        ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
    }
	
	//确定最小低层数组的最大容量
	private static int calculateCapacity(Object[] elementData, int minCapacity) {
        if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
            return Math.max(DEFAULT_CAPACITY, minCapacity);
        }
        return minCapacity;
    }

	
	private void ensureExplicitCapacity(int minCapacity) {
        modCount++;
        // 如过添加后的list.size>低层数组的容量,扩容
        if (minCapacity - elementData.length > 0)
        	//扩容大小,为原大小的1.5倍
            grow(minCapacity);
    }
	
	//扩容
	private void grow(int minCapacity) {
        // overflow-conscious code
        int oldCapacity = elementData.length;
        //原大小的1.5倍
        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);
    }	

	//扩容,返回一个新的数组
	public static <T,U> T[] copyOf(U[] original, int newLength, Class<? extends T[]> newType) 
        @SuppressWarnings("unchecked")
        T[] copy = ((Object)newType == (Object)Object[].class)
            ? (T[]) new Object[newLength]
            : (T[]) Array.newInstance(newType.getComponentType(), newLength);
        System.arraycopy(original, 0, copy, 0,
                         Math.min(original.length, newLength));
        return copy;
    }

总结:

  1. 是否需要扩容。
  2. 需要,调用grow方法。
  3. 第一次扩容后,如果容量还是小于minCapacity,就将容量扩充为minCapacity。
  4. 足够:直接添加。
  5. 不足够:扩容。

add(int index, E element)

	public void add(int index, E element) {
		//检查下标是否越界
        rangeCheckForAdd(index);
		//是否需要扩容
        ensureCapacityInternal(size + 1);  // Increments modCount!!
        //调用copy函数
        System.arraycopy(elementData, index, elementData, index + 1,
                         size - index);
        //添加
        elementData[index] = element;
        //list大小+1
        size++;
    }

get( int index)

	//获取index
	public E get(int index) {
			//检查index是否在list的范围中
            rangeCheck(index);
            //fail-fast(快速失败机制)检查
            checkForComodification();
            //返回元素
            return ArrayList.this.elementData(offset + index);
        }
     
     //判断是否越界
	 private void rangeCheck(int index) {
	 		//越界抛出异常
            if (index < 0 || index >= this.size)
                throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
     }

总结:

  1. 检查角标
  2. 快速失败机制判断
  3. 返回值

set(int index, E element)

	public E set(int index, E element) {
		//检查是否越界,是否存在集合大小中
        rangeCheck(index);
		//获取index位置的元素
        E oldValue = elementData(index);
        //覆盖index位置的元素
        elementData[index] = element;
        //返回返回老的值
        return oldValue;
    }

总结:

  1. 检查时候越界
  2. 获取index元素赋值给oldValue
  3. 修改index的元素
  4. 返回oldValue

remove(int index)

	public E remove(int index) {
		//检查下标是否存在
        rangeCheck(index);
		//快速失败机制
        modCount++;
        //获取相应下标值
        E oldValue = elementData(index);
		//需要左移的个数
        int numMoved = size - index - 1;
        //调用copy
        if (numMoved > 0)
            System.arraycopy(elementData, index+1, elementData, index,
                             numMoved);
        //GC回收
        elementData[--size] = null; // clear to let GC do its work

        return oldValue;
    }

总结:

  1. 检查角标
  2. 删除元素
  3. 计算出需要移动的个数,并移动
  4. 设置为null,让Gc回收

注:ArrayList(int initialCapacity)指定类集合中数组的大小,但没有集合的实际大小是由size属性来判断的,调用set方法会出现异常,ArrayList集合不适合做队列,但数组适合做循环队列

ArrayList集合常用方法

  • boolean add(E e)

将指定的元素添加到此列表的尾部。

  • void add(int index, E element)

将指定的元素插入此列表中的指定位置。

  • boolean addAll(Collection c)

按照指定 collection 的迭代器所返回的元素顺序,将该 collection 中的所有元素添加到此列表的尾部。

  • boolean addAll(int index, Collection c)

从指定的位置开始,将指定 collection 中的所有元素插入到此列表中。

  • void clear()

移除此列表中的所有元素。

  • Object clone()

返回此 ArrayList 实例的浅表副本。

  • boolean contains(Object o)

如果此列表中包含指定的元素,则返回 true。

  • void ensureCapacity(int minCapacity)

如有必要,增加此 ArrayList 实例的容量,以确保它至少能够容纳最小容量参数所指定的元素数。

  • E get(int index)

返回此列表中指定位置上的元素。

  • int indexOf(Object o)

返回此列表中首次出现的指定元素的索引,或如果此列表不包含元素,则返回 -1。

  • boolean isEmpty()

如果此列表中没有元素,则返回 true

  • int lastIndexOf(Object o)

返回此列表中最后一次出现的指定元素的索引,或如果此列表不包含索引,则返回 -1。

  • E remove(int index)

移除此列表中指定位置上的元素。

  • boolean remove(Object o)

移除此列表中首次出现的指定元素(如果存在)。

  • protected void removeRange(int fromIndex, int toIndex)

移除列表中索引在 fromIndex(包括)和 toIndex(不包括)之间的所有元素。

  • E set(int index, E element)

用指定的元素替代此列表中指定位置上的元素。

  • int size()

返回此列表中的元素数。

  • Object[] toArray()

按适当顺序(从第一个到最后一个元素)返回包含此列表中所有元素的数组。

  • T[] toArray(T[] a)

按适当顺序(从第一个到最后一个元素)返回包含此列表中所有元素的数组;返回数组的运行时类型是指定数组的运行时类型。

  • void trimToSize()

将此 ArrayList 实例的容量调整为列表的当前大小。

LinkedList

LinkedList底层是双向链表

基本结构

从结构上,我们还看到了LinkedList实现了Deque接口,因此,我们可以操作LinkedList像操作队列和栈一样~

	//链表长度
	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;
        }
    }

构造方法

	//空的构造函数
	 public LinkedList() {
    }
    //自带集合的构造函数
    public LinkedList(Collection<? extends E> c) {
        this();
        addAll(c);
    }

add(E e)

	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;
        //大小+1
        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) {
        // 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) {
   
		//如果index在前半段
        if (index < (size >> 1)) {
            Node<E> x = first;
            for (int i = 0; i < index; i++)
                x = x.next;
            return x;
        } else {//index在后半段
            Node<E> x = last;
            for (int i = size - 1; i > index; i--)
                x = x.prev;
            return x;
        }
    }

set方法

set方法和get方法其实差不多,根据下标来判断是从头遍历还是从尾遍历

	public E set(int index, E element) {
		//检查越界
        checkElementIndex(index);
        //获取老的值
        Node<E> x = node(index);
        //赋值
        E oldVal = x.item;
        //将老的值修改
        x.item = element;
        return oldVal;
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值