ArrayList源码分析1.8

一、ArrayList属性:

1、ArrayList属性主要就是当前数组长度size,以及存放数组的对象elementData数组

public class ArrayList<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, Serializable {
    	// 序列化id
    	private static final long serialVersionUID = 8683452581122892189L;
    	// 默认初始的容量
    	private static final int DEFAULT_CAPACITY = 10;
    	// 一个空对象
    	private static final Object[] EMPTY_ELEMENTDATA = new Object[0];
    	// 一个空对象,如果使用默认构造函数创建,则默认对象内容默认是该值
    	private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = new Object[0];
    	// 当前数据对象存放地方,当前对象不参与序列化
    	transient Object[] elementData;
    	// 当前数组长度
    	private int size;
    	// 数组最大长度
    	private static final int MAX_ARRAY_SIZE = 2147483639;
    }

二、ArrayList构造函数

1、不传入参数,则使用默认无参构建方法创建ArrayList对象

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

2、入参数,则代表指定ArrayList的初始数组长度,传入参数如果是大于等于0,则使用用户的参数初始化,如果用户传入的参数小于0,则抛出异常

    public ArrayList(int initialCapacity) {
        if (initialCapacity > 0) {
            this.elementData = new Object[initialCapacity];
        } else if (initialCapacity == 0) {
            this.elementData = EMPTY_ELEMENTDATA;
        } else {
            throw new IllegalArgumentException("Illegal Capacity: "+
                                               initialCapacity);
        }
    }

三、常用方法:

1、add(E e) 方法:

    public boolean add(E e) {
        ensureCapacityInternal(size + 1);  // Increments modCount!!
        elementData[size++] = e;
        return true;
    }

确保添加的元素有地方存储,当第一次添加元素的时候this.size+1 的值是1,所以第一次添加的时候会将当前elementData数组的长度变为10

    private void ensureCapacityInternal(int minCapacity) {
        if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
            minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
        }
 
        ensureExplicitCapacity(minCapacity);
    }

将修改次数(modCount)自增1,判断是否需要扩充数组长度,判断条件就是用当前所需的数组最小长度与数组的长度对比,如果大于0,则增长数组长度

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

如果当前的数组已使用空间(size)加1之后 大于数组长度,则增大数组容量,扩大为原来的1.5倍

	private void grow(int arg0) {
		int arg1 = this.elementData.length;
		int arg2 = arg1 + (arg1 >> 1);
		if (arg2 - arg0 < 0) {
			arg2 = arg0;
		}
 
		if (arg2 - 2147483639 > 0) {
			arg2 = hugeCapacity(arg0);
		}
 
		this.elementData = Arrays.copyOf(this.elementData, arg2);
	}

2、add(int index, E element)方法:加元素到数组中指定位置的时候,要将该位置及其后边所有的元素都整块向后复制一位

    public void add(int index, E element) {
        rangeCheckForAdd(index);
 
        ensureCapacityInternal(size + 1);  // Increments modCount!!
         //这个方法就是用来在插入元素之后,要将index之后的元素都往后移一位
        System.arraycopy(elementData, index, elementData, index + 1,    
                         size - index);
        elementData[index] = element;
        size++;
    }
private void rangeCheckForAdd(int index) {
        if (index > size || index < 0)   //插入的位置肯定不能大于size 和小于0
			//如果是,就报这个越界异常
            throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
    }

3、get方法:返回指定位置上的元素时,可以通过索引直接获取(O(1))

        public E get(int index) {
            rangeCheck(index);
            checkForComodification();
            return ArrayList.this.elementData(offset + index);
        }

4、set方法:set的位置小于当前数组的长度(size)并且大于0,获取指定位置(index)元素,然后放到oldValue存放,将需要设置的元素放到指定的位置(index)上,然后将原来位置上的元素oldValue返回给用户

    public E set(int index, E element) {
        rangeCheck(index);
 
        E oldValue = elementData(index);
        elementData[index] = element;
        return oldValue;
    }

5、contains方法:遍历数组中的每一个元素作对比,如果找到对于的元素,则返回true,没有找到则返回false

    public boolean contains(Object o) {
        return indexOf(o) >= 0;
    }
    public int indexOf(Object o) {
        if (o == null) {
            for (int i = 0; i < size; i++)
                if (elementData[i]==null)
                    return i;
        } else {
            for (int i = 0; i < size; i++)
                if (o.equals(elementData[i]))
                    return i;
        }
        return -1;
    }

6、remove(int)方法:通过索引删除指定位置上的元素

public E remove(int index) {
        rangeCheck(index);//检查index的合理性

        modCount++;
        E oldValue = elementData(index);//通过索引直接找到该元素

        int numMoved = size - index - 1;//计算要移动的位数。
        if (numMoved > 0)
			//用来移动元素的
            System.arraycopy(elementData, index+1, elementData, index,
                             numMoved);
		//将--size上的位置赋值为null,让gc(垃圾回收机制)更快的回收它。
        elementData[--size] = null; // clear to let GC do its work
		//返回删除的元素。
        return oldValue;
    }

7、remove(Object):arrayList是可以存放null值

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])) {
                    fastRemove(index);
                    return true;
                }
        }
        return false;
    }
 private void fastRemove(int index) {
        modCount++;
        int numMoved = size - index - 1;
        if (numMoved > 0)
            System.arraycopy(elementData, index+1, elementData, index,
                             numMoved);
        elementData[--size] = null; // clear to let GC do its work
    }

总结:
1、arrayList可以存放null
2、arrayList本质上就是一个elementData数组
3、arrayList区别于数组的地方在于能够自动扩展大小(1.5倍),其中关键的方法就是gorw()方法
4、arrayList是数组的特性,查询方面会很快,插入删除射界数据的位置移动性能下降很多
5、arrayList实现了RandomAccess,所以在遍历它的时候推荐使用for循环

猜你喜欢

转载自blog.csdn.net/weixin_43185598/article/details/87969041