ArrayList源码分析

本文详细解析了ArrayList类的成员变量、构造方法和关键方法,如添加、移除、扩容等,助你理解容器数据结构实现原理。

成员变量和常量

//存储数据的数组
transient Object[] elementData;

//数据的个数
private int size;

//默认的容量
private static final int DEFAULT_CAPACITY = 10;

//空数组
private static final Object[] EMPTY_ELEMENTDATA = {};

//空数组
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};

//容器被修改的次数, 数组中数据的添加,删除  会修改该参数
protected transient int modCount = 0;

//最大容量判定值
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;

构造方法

	//指定容量的构造函数
	public ArrayList(int initialCapacity) {
		//elementData初始化为指定大小的数组
        if (initialCapacity > 0) {
            this.elementData = new Object[initialCapacity];
        } else if (initialCapacity == 0) {
            this.elementData = EMPTY_ELEMENTDATA;
        } else {
            throw new IllegalArgumentException("Illegal Capacity: "+
                                               initialCapacity);
        }
    }
    //没有指定容量
    public ArrayList() {
        //先给一个空数组
        this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
    }
    //将另一个容器的数组复制到当前数组
    public ArrayList(Collection<? extends E> c) {
    	//获取入参集合的数组数据。赋值给elementData 
        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);
        }
        //入参的集合为空,直接将elementData赋值为空数组
        else {
            // replace with empty array.
            this.elementData = EMPTY_ELEMENTDATA;
        }
    }

添加数据相关的方法

	//顺序添加数据
	public boolean add(E e) {
		//检查容量是否足够,不够,则要申请一个更大的数组,并复制原数组的数据到新数组, 入参为当前容器数据个数+1
        ensureCapacityInternal(size + 1);  // Increments modCount!!
        //赋值,并且更新size
        elementData[size++] = e;
        return true;
    }
    //向指定位置添加数据
    public void add(int index, E element) {
    	//检查index的合法性,index不能为负数,不能大于size,否则抛异常
        rangeCheckForAdd(index);
		
		//检查容量是否足够,不够,则要申请一个更大的数组,并复制原数组的数据到新数组,
        ensureCapacityInternal(size + 1);  // Increments modCount!!
        //将数组index位置开始的数据,全部复制到index+1开始之后的位置,(通俗点说,index位置及之后的数据全部向后顺移一个位置)
        System.arraycopy(elementData, index, elementData, index + 1,
                         size - index);
        //直接给index位置赋值
        elementData[index] = element;
        //size 加一
        size++;
    }
    public boolean addAll(Collection<? extends E> c) {
    	//获取集合的数组数据
        Object[] a = c.toArray();
        //获取数据的长度
        int numNew = a.length;
        //检查容量是否足够,不够,则要申请一个更大的数组,并复制原数组的数据到新数组,
        ensureCapacityInternal(size + numNew);  // Increments modCount
        //将a的数据复制到 elementData 的 size开始以及之后的位置
        System.arraycopy(a, 0, elementData, size, numNew);
        //size需要加上添加的数据的个数
        size += numNew;
        //返回值为 添加进来的数据个数是否为0
        return numNew != 0;
    }
    public boolean addAll(int index, Collection<? extends E> c) {
    	//检查添加的位置是否合法
        rangeCheckForAdd(index);
		
		//获取集合的数组数据
        Object[] a = c.toArray();
        //获取数据的长度
        int numNew = a.length;
		
		//检查容量是否足够,不够,则要申请一个更大的数组,并复制原数组的数据到新数组,
        ensureCapacityInternal(size + numNew);  // Increments modCount
		
		//原数组要移动的数据的个数
        int numMoved = size - index;
        //大于0 说明添加的index的位置有数据,需要后移index及以后的数据 , 使得空出来的位置可以放入添加进来的数据
        if (numMoved > 0)
            System.arraycopy(elementData, index, elementData, index + numNew,
                             numMoved);
		
		//将添加进来的数据复制到放入到elementData中
        System.arraycopy(a, 0, elementData, index, numNew);
        //size需要加上添加的数据的个数
        size += numNew;
        //返回值为 添加进来的数据个数是否为0
        return numNew != 0;
    }
    
    //ArrayList的toArray方法
	public Object[] toArray() {
        return Arrays.copyOf(elementData, size);
    }

ensureCapacityInternal方法

	//入参为需求的容量大小
	private void ensureCapacityInternal(int minCapacity) {
        ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
    }
    private static int calculateCapacity(Object[] elementData, int minCapacity) {
    	//如果elementData为空数组
        if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
        	//返回DEFAULT_CAPACITY(10) 和 需求的容量大小 的 更大的值
            return Math.max(DEFAULT_CAPACITY, minCapacity);
        }
        //如果不是空数组,直接返回需求的容量大小
        return minCapacity;
    }
    private void ensureExplicitCapacity(int minCapacity) {
 		//modCount加一
        modCount++;

        // 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 + (oldCapacity >> 1);
        //如果新数组的容量大小 小于 需求的容量大小
        if (newCapacity - minCapacity < 0)
        	//则新的数组的容量大小为需求的容量大小
            newCapacity = minCapacity;
        //新容量超过了MAX_ARRAY_SIZE 
        if (newCapacity - MAX_ARRAY_SIZE > 0)
            newCapacity = hugeCapacity(minCapacity);
        // minCapacity is usually close to size, so this is a win:
        //将原数组cpoy给新数组,并将新数组赋值给elementData 
        elementData = Arrays.copyOf(elementData, newCapacity);
    }
    private static int hugeCapacity(int minCapacity) {
    	//需求的容量已经溢出int能表示的最大值,直接抛异常
        if (minCapacity < 0) // overflow
            throw new OutOfMemoryError();
        //需求的容量大于MAX_ARRAY_SIZE , 则返回 Integer.MAX_VALUE 
        //否则返回MAX_ARRAY_SIZE
        return (minCapacity > MAX_ARRAY_SIZE) ?
            Integer.MAX_VALUE :
            MAX_ARRAY_SIZE;
    }

rangeCheckForAdd方法

	private void rangeCheckForAdd(int index) {
		//index 不能大于size ,不允许添加的数据的数组前面有空位置
        if (index > size || index < 0)
            throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
    }
    private String outOfBoundsMsg(int index) {
        return "Index: "+index+", Size: "+size;
    }

get方法

	public E get(int index) {
		//检查index是否合法
        rangeCheck(index);
		
		//返回数组对应下标的数据
        return elementData(index);
    }
    //Object数组要进行强转
    E elementData(int index) {
        return (E) elementData[index];
    }

set方法

	public E set(int index, E element) {
		//检查index是否合法
        rangeCheck(index);
		
		//获取数组指定下标的数据
        E oldValue = elementData(index);
        //将数组指定下标的数据设置为入参的element
        elementData[index] = element;
        //返回原本的值
        return oldValue;
    }

remove方法

	//按下标移除数据
	public E remove(int index) {
		//检查index合法性
        rangeCheck(index);
		
		//modCount加一
        modCount++;
	    //获取原本下标位置的值
        E oldValue = elementData(index);
		
		//需要将后面位置的数据复制到前面来补充该位置
		//计算需要复制的数据的个数
        int numMoved = size - index - 1;
        //被移除的数据不是size-1位置的数据,则numMoved大于0
        if (numMoved > 0)
        	//将index+1及以后位置的数据 复制到 index及以后位置上。
            System.arraycopy(elementData, index+1, elementData, index,
                             numMoved);
        //上面复制完成后,size位置的数据已经在size-1的位置存在了,移除掉size位置的数据
        //或者如果本来移除的就是最后一个数据,直接置空
        elementData[--size] = null; // clear to let GC do its work
		//返回被移除的值
        return oldValue;
    }
    //按 数据的equals方法 移除数据
    public boolean remove(Object o) {
		
    	//如果入参值为null
        if (o == null) {
        	//遍历数组
            for (int index = 0; index < size; index++)
            	//如果该值为null
                if (elementData[index] == null) {
                	//移除数组上该位置的数据
                    fastRemove(index);
                    return true;
                }
        } 
        else {
	        //遍历数组
            for (int index = 0; index < size; index++)
            	//调用入参的equals方法和数组中的数据比较
                if (o.equals(elementData[index])) {
                	//移除数组上该位置的数据
                    fastRemove(index);
                    return true;
                }
        }
        return false;

		//显然这里找到一个符合条件的数据删除后,就返回了,如果还有符合条件的数据并不会接着移除
	
    }
    private void fastRemove(int index) {
    	//modCount增加
        modCount++;
        //计算需要复制的数据的个数
        int numMoved = size - index - 1;
        //被移除的数据不是size-1位置的数据,则numMoved大于0
        //将index+1及以后位置的数据 复制到index及以后位置上。
        if (numMoved > 0)
        	//将index+1及以后位置的数据 复制到 index及以后位置上。
            System.arraycopy(elementData, index+1, elementData, index,
                             numMoved);   
        //返回被移除的值
        elementData[--size] = null; // clear to let GC do its work
    }

clear方法

public void clear() {
		//modCount加1
        modCount++;
		
		//将数组中的数据全部置为null
        // clear to let GC do its work
        for (int i = 0; i < size; i++)
            elementData[i] = null;
		
		//size置为0
        size = 0;
    }

查找数据在数组位置

	//从头往后找,找到就返回对应的下标
	public int indexOf(Object o) {
        if (o == null) {
            for (int i = 0; i < size; i++)
                if (elementData[i]==null)
                    return i;
        } 
        //找的不是null值,使用equals来比较数据
        else {
            for (int i = 0; i < size; i++)
                if (o.equals(elementData[i]))
                    return i;
        }
        return -1;
    }
    //从后往前找,找到就返回对应的下标
    public int lastIndexOf(Object o) {
        if (o == null) {
            for (int i = size-1; i >= 0; i--)
                if (elementData[i]==null)
                    return i;
        } 
        //找的不是null值,使用equals来比较数据
        else {
            for (int i = size-1; i >= 0; i--)
                if (o.equals(elementData[i]))
                    return i;
        }
        return -1;
    }

Iterator的相关方法

	public Iterator<E> iterator() {
		//实例化Itr对象
        return new Itr();
    }
    private class Itr implements Iterator<E> {
    	//下一个返回的数据的下标
        int cursor;       // index of next element to return
        //当前遍历出来的数据的下标
        int lastRet = -1; // index of last element returned; -1 if no such
        //初始expectedModCount为modCount
        int expectedModCount = modCount;

        Itr() {}
		
		//cursor不等于size,则还有数据可以遍历
        public boolean hasNext() {
            return cursor != size;
        }

        @SuppressWarnings("unchecked")
        //获取数据
        public E next() {
        	//检查expectedModCount 和 modCount是否相等,不等则抛出异常(其他线程修改了当前集合的数据,则本次遍历是无效的)
            checkForComodification();
            //将cursor赋值给i
            int i = cursor;
            //超过了size , 抛出异常
            if (i >= size)
                throw new NoSuchElementException();
            //获取数组的数据
            Object[] elementData = ArrayList.this.elementData;
            //超过数组长度,抛出异常
            if (i >= elementData.length)
                throw new ConcurrentModificationException();
            //将cursor 加一 ,为下一个要获取的数据的下标
            cursor = i + 1;
            //将i赋值给lastRet 
            //返回lastRet 位置的数据
            return (E) elementData[lastRet = i];
        }
		
		//移除数据
        public void remove() {
            if (lastRet < 0) 
                throw new IllegalStateException();
             //检查expectedModCount 和 modCount是否相等,不等则抛出异常(其他线程修改了当前集合的数据,则本次遍历时无效的)
            checkForComodification();

            try {
            	//调用外部类ArrayList的remove方法,移除数组中该下标的数据
                ArrayList.this.remove(lastRet);
                //修改cursor 为lastRet , lastRet位置的数据被移除,则后面的数据全部被向前复制了一遍 ,则 lastRet为下一次遍历获取的数据的下标
                cursor = lastRet;
                //lastRet 修改为 -1
                lastRet = -1;
                //调用remove方法,改变了modCount
                //修改expectedModCount 为 modCount
                expectedModCount = modCount;
            } catch (IndexOutOfBoundsException ex) {
                throw new ConcurrentModificationException();
            }
        }
    }
	final void checkForComodification() {
		//Itr 实例化时的expectedModCount 不等于modCount ,则抛异常
        if (modCount != expectedModCount)
            throw new ConcurrentModificationException();
    }

subList方法,所有对数据的操作的方法就不一一看了,很简单了,都是使用parent 或者 ArrayList.this.elementData (原本的数组)去操作的。

	public List<E> subList(int fromIndex, int toIndex) {
		//检查截取下标的合法性
        subListRangeCheck(fromIndex, toIndex, size);
        //返回SubList对象,持有了this(ArrayList对象)
        return new SubList(this, 0, fromIndex, toIndex);
    }

    static void subListRangeCheck(int fromIndex, int toIndex, int size) {
        if (fromIndex < 0)
            throw new IndexOutOfBoundsException("fromIndex = " + fromIndex);
        if (toIndex > size)
            throw new IndexOutOfBoundsException("toIndex = " + toIndex);
        if (fromIndex > toIndex)
            throw new IllegalArgumentException("fromIndex(" + fromIndex +
                                               ") > toIndex(" + toIndex + ")");
    }

	SubList(AbstractList<E> parent,
                int offset, int fromIndex, int toIndex) {
            //parent为实例化传入进来的原本的ArrayList对象
            this.parent = parent;
            this.parentOffset = fromIndex;
            this.offset = offset + fromIndex;
            this.size = toIndex - fromIndex;
            this.modCount = ArrayList.this.modCount;
    }

ArrayList还是比较简单的,可以作为学习源码的入门类。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值