List集合源码深度解析

ArrayList源码分析

自定义List集合接口
package com.mayikt.ext;

/**
 * @Description: 自定义List集合
 * @Author: ChenYi
 * @Date: 2020/06/09 20:43
 **/

public interface MayiktList<E> {
    /**
     * 集合的大小
     *
     * @return
     */
    int size();

    /**
     * 往集合中添加元素
     *
     * @param e
     * @return
     */
    boolean add(E e);

    /**
     * 通过索引获取集合的元素
     *
     * @param index
     * @return
     */
    E get(int index);
}
自定义ArrayList类
package com.mayikt.ext.impl;

import com.mayikt.ext.MayiktList;

import java.util.Arrays;

/**
 * @Description: 自定义ArrayList
 * @Author: ChenYi
 * @Date: 2020/06/09 20:46
 **/

public class MayiktArrayList<E> implements MayiktList<E> {
    /**
     * 初始化空的数组
     */
    private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
    /**
     * 数组的容量,transient代表该变量不能被序列化
     */
    transient Object[] elementData;
    /**
     * 集合的大小
     */
    private int size;
    /**
     * ArrayList默认的初始容量
     */
    private static final int DEFAULT_CAPACITY = 10;


    private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;

    protected transient int modCount = 0;

    public MayiktArrayList() {
        this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
    }

    @Override
    public int size() {
        return this.size;
    }

    @Override
    public boolean add(E e) {
        //初始化集合的大小
        ensureCapacityInternal(size + 1);
        //赋值
        elementData[size++] = e;
        return true;
    }

    @Override
    public E get(int index) {
        return (E) elementData[index];
    }

    @Override
    public E remove(int index) {
        //检测数组是否越界
        rangeCheck(index);
        //保证线程安全性
        modCount++;
        E oldValue = get(index);
        int numMoved = size - index - 1;
        //检测如果是删除最后一位的话直接把最后一位置空
        if (numMoved > 0) {
            System.arraycopy(elementData, index + 1, elementData, index,
                    numMoved);
        }
        //最后索引位置置空
        elementData[--size] = null;

        return oldValue;
    }

    private void ensureCapacityInternal(int minCapacity) {

        if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
            //没有指定集合容量的大小并且是第一次添加元素的时候进来
            //minCapacity=0+1   DEFAULT_CAPACITY=10
            minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
        }
        //第一次初始化的集合的大小为10
        ensureExplicitCapacity(minCapacity);
    }

    private void ensureExplicitCapacity(int minCapacity) {
        //保证线程的安全性,如果同时写入的话就可能报错
        modCount++;
        //判断数组是否需要扩容
        if (minCapacity - elementData.length > 0) {
            grow(minCapacity);
        }
    }

    /**
     * 判断数组是否越界
     *
     * @param index
     */
    private void rangeCheck(int index) {
        if (index >= size) {
            throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
        }
    }

    private String outOfBoundsMsg(int index) {
        return "Index: " + index + ", Size: " + size;
    }

    private void grow(int minCapacity) {
        // 第一次elementData为空数组 0
        int oldCapacity = elementData.length;
        /**
         *  >>位运算  向右移动相当于/2  左移相当于*2
         *   0+0/2=0
         */
        int newCapacity = oldCapacity + (oldCapacity >> 1);
        // 0-10
        if (newCapacity - minCapacity < 0) {
            //第一次扩容的时候才进来 10
            newCapacity = minCapacity;
        }
        //集合的最大容量是2 的21次方
        if (newCapacity - MAX_ARRAY_SIZE > 0) {
            newCapacity = hugeCapacity(minCapacity);
        }
        elementData = Arrays.copyOf(elementData, newCapacity);
    }


    private static int hugeCapacity(int minCapacity) {
        if (minCapacity < 0) {
            throw new OutOfMemoryError();
        }
        return (minCapacity > MAX_ARRAY_SIZE) ?
                Integer.MAX_VALUE :
                MAX_ARRAY_SIZE;
    }
}


总结:

  • 使用无参构建函数new出ArrayList集合的时候,数组的容量是0,elementData是一个空的数组
  • 第一次添加的时候才会初始化数组的大小,会调用grow方法进行扩容,初始化的大小为10
  • 每次扩容的时候,数组的长度增加0.5倍
  • 数组最大的长度是Interger的最大值
  • 集合删除元素之后,数组是不会缩容的,对应的位置置为null
  • 由于ArrayList是线程不安全的,在高并发的情况下会出现Fail-Fast,所以里面用了一个modCount来保证线程的安全。

CopyOnWriteArrayList源码分析

自定义的CopyOnWriteArrayList类
package com.mayikt.ext.impl;

import com.mayikt.ext.MayiktList;

import java.util.Arrays;
import java.util.concurrent.locks.ReentrantLock;

/**
 * @Description: 自定义CopyOnWriteArrayList
 * @Author: ChenYi
 * @Date: 2020/06/11 07:46
 **/

public class MayiktCopyOnWriteArrayList<E> implements MayiktList<E> {
    final transient ReentrantLock lock = new ReentrantLock();
    private transient volatile Object[] array;

    @Override
    public int size() {
        return 0;
    }

    @Override
    public boolean add(E e) {
        final ReentrantLock lock = this.lock;
        //加lock能够保证线程的安全
        lock.lock();
        try {
            Object[] elements = getArray();
            int len = elements.length;
            //每次添加都要把之前的数组复制到新的数组中
            Object[] newElements = Arrays.copyOf(elements, len + 1);
            newElements[len] = e;
            setArray(newElements);
            return true;
        } finally {
            lock.unlock();
        }
    }

    final Object[] getArray() {
        return array;
    }


    public MayiktCopyOnWriteArrayList() {
        setArray(new Object[0]);
    }

    final void setArray(Object[] a) {
        array = a;
    }

    @Override
    public E get(int index) {
        return get(getArray(), index);
    }

    private E get(Object[] a, int index) {
        return (E) a[index];
    }

    @Override
    public E remove(int index) {
        final ReentrantLock lock = this.lock;
        lock.lock();
        try {
            Object[] elements = getArray();
            int len = elements.length;
            E oldValue = get(elements, index);
            int numMoved = len - index - 1;
            if (numMoved == 0) {
                setArray(Arrays.copyOf(elements, len - 1));
            } else {
                Object[] newElements = new Object[len - 1];
                System.arraycopy(elements, 0, newElements, 0, index);
                System.arraycopy(elements, index + 1, newElements, index,
                        numMoved);
                setArray(newElements);
            }
            return oldValue;
        } finally {
            lock.unlock();
        }
    }
}

总结:

  • 使用无参构建对象的时候,默认的数组也是空的
  • 每次添加元素的时候都会加Lock锁,原来的数组长度加1,创建出新的数组,然后把之前的值放进去,没有存在扩容的操作。
  • 读的时候是没有加Lock锁的,所以读取的时候效率比较快。

Vector源码解析

自定义的Vector类
package com.mayikt.ext.impl;

import com.mayikt.ext.MayiktList;

import java.util.Arrays;

/**
 * @Description: 自定义Vector集合
 * @Author: ChenYi
 * @Date: 2020/06/11 08:19
 **/

public class MayiktVector<E> implements MayiktList<E> {
    protected int capacityIncrement;
    protected Object[] elementData;

    protected transient int modCount = 0;

    protected int elementCount;

    private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;

    public MayiktVector() {
        this(10);
    }

    public MayiktVector(int initialCapacity) {
        this(initialCapacity, 0);
    }

    public MayiktVector(int initialCapacity, int capacityIncrement) {
        super();
        if (initialCapacity < 0) {
            throw new IllegalArgumentException("Illegal Capacity: " +
                    initialCapacity);
        }
        this.elementData = new Object[initialCapacity];
        this.capacityIncrement = capacityIncrement;
    }

    @Override
    public int size() {
        return 0;
    }

    @Override
    public synchronized boolean add(E e) {
        modCount++;
        ensureCapacityHelper(elementCount + 1);
        elementData[elementCount++] = e;
        return true;
    }

    private void ensureCapacityHelper(int minCapacity) {
        // overflow-conscious code
        if (minCapacity - elementData.length > 0) {
            grow(minCapacity);
        }
    }

    private void grow(int minCapacity) {
        // overflow-conscious code
        int oldCapacity = elementData.length;
        int newCapacity = oldCapacity + ((capacityIncrement > 0) ?
                capacityIncrement : oldCapacity);
        if (newCapacity - minCapacity < 0) {
            newCapacity = minCapacity;
        }
        if (newCapacity - MAX_ARRAY_SIZE > 0) {
            newCapacity = hugeCapacity(minCapacity);
        }
        elementData = Arrays.copyOf(elementData, newCapacity);
    }

    private static int hugeCapacity(int minCapacity) {
        if (minCapacity < 0) {
            throw new OutOfMemoryError();
        }
        return (minCapacity > MAX_ARRAY_SIZE) ?
                Integer.MAX_VALUE :
                MAX_ARRAY_SIZE;
    }

    @Override
    public synchronized E get(int index) {
        if (index >= elementCount) {
            throw new ArrayIndexOutOfBoundsException(index);
        }
        return elementData(index);
    }

    E elementData(int index) {
        return (E) elementData[index];
    }

    @Override
    public synchronized E remove(int index) {
        modCount++;
        if (index >= elementCount) {
            throw new ArrayIndexOutOfBoundsException(index);
        }
        E oldValue = elementData(index);

        int numMoved = elementCount - index - 1;
        if (numMoved > 0) {
            System.arraycopy(elementData, index + 1, elementData, index,
                    numMoved);
        }
        elementData[--elementCount] = null;
        return oldValue;
    }
}

总结:

  • 使用无参构建创建对象的时候默认创建容量为10的数组
  • 存在扩容的原理,跟ArrayList一样,只是线程是安全的,在修改或者读取数据的时候都加了synchronized关键字,效率很低,capacityIncrement没有指定的时候,扩容默认是扩大一倍的

LinkeList源码分析

自定义的LinkList类

package com.mayikt.ext.impl;

import com.mayikt.ext.MayiktList;

import java.util.Objects;

/**
 * @Description:自定义LinkList集合
 * @Author: ChenYi
 * @Date: 2020/06/20 09:11
 **/

public class MayiktLinkList<E> implements MayiktList<E> {
    transient int size = 0;
    transient MayiktLinkList.Node<E> first;
    transient MayiktLinkList.Node<E> last;
    protected transient int modCount = 0;

    public MayiktLinkList() {
    }

    @Override
    public int size() {
        return size;
    }

    @Override
    public boolean add(E e) {
        linkLast(e);
        return true;
    }

    private void linkLast(E e) {
        final MayiktLinkList.Node<E> l = last;
        final MayiktLinkList.Node<E> newNode = new MayiktLinkList.Node<>(l, e, null);
        last = newNode;
        if (l == null) {
            //链表的第一个元素
            first = newNode;
        } else {
            l.next = newNode;
        }
        size++;
        modCount++;
    }

    @Override
    public E get(int index) throws Exception {
        checkElementIndex(index);
        return (E) node(index).item;
    }

    private MayiktLinkList.Node node(int index) {
        //采用折半查找
        MayiktLinkList.Node x;
        if (index <= size >> 1) {
            x = first;
            for (int i = 0; i < index; i++) {
                x = x.next;
            }
        } else {
            x = last;
            for (int i = size - 1; i > index; i--) {
                x = x.prev;
            }
        }
        return x;
    }

    private void checkElementIndex(int index) throws Exception {
        if (isElementIndex(index)) {
            return;
        }
        throw new Exception("数组越界!!!");
    }

    private boolean isElementIndex(int index) {
        return index >= 0 && index < size;
    }

    @Override
    public E remove(int index) throws Exception {
        checkElementIndex(index);
        return unlink(node(index));
    }

    private E unlink(Node current) {
        //要删除节点的上节点
        Object item = current.item;
        Node prev = current.prev;
        //要删除节点的下节点
        Node next = current.next;
        //说明删除的是第一个元素
        if (Objects.isNull(prev)) {
            first = next;
        } else {
            prev.next = next;
            //设置为空给垃圾回收
            current.prev = null;
        }
        //说明删除最后一个元素
        if (Objects.isNull(next)) {
            last = prev;
        } else {
            next.prev = prev;
            //设置为空给gc回收
            current.next = null;
        }
        //设置为空
        current.item = null;
        size--;
        modCount++;
        return (E) item;
    }

    private static class Node<E> {
        E item;
        MayiktLinkList.Node<E> next;
        MayiktLinkList.Node<E> prev;

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

总结:

  • 底层是采用双链表的数据结构来存储数据的,底层采用了静态内部类Node节点存放节点元素,包含指向上个节点的指针prev,当前的数据item,下个节点的指针next,链表是不需要扩容的,因为长度是可以不断变化的,数组的数据结构才需要扩容
  • add原理是一直在链表之后添加
  • get的原理是采用折半查询,查询效率比较低,时间复杂度是O(n/2)
  • remove的原理是改变上下节点的指针

参考:来自蚂蚁课堂

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值