Java ArrayList源码分析(JDK8)

ArrayList简介
  • ArrayList是Java语言中常用的集合,他的底层由数组实现,因此继承了数据数据结构的优点:查询效率高(时间复杂度O(1)),插入删除慢(时间复杂度O(N))。
  • ArrayList的构造方法中可以设置容器初始化容量大小,默认容量长度为10,当ArrayList到达容量阈值之后,会进行每次0.5倍的扩容。

附ArrayList源码如下:

成员变量
  public class ArrayList<E> extends AbstractList<E>
	            implements List<E>, RandomAccess, Cloneable, java.io.Serializable
	    {
	        private static final long serialVersionUID = 8683452581122892189L;
	    
	        /* 默认容量长度 10*/
	        private static final int DEFAULT_CAPACITY = 10;
	    
	        /* 没有数据的空数组*/
	        private static final Object[] EMPTY_ELEMENTDATA = {};
	    
	        /* 集合初始化时没有给长度,使用默认长度(10)的数组 */
	        private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
	    
	        /*transient 修饰的变量 实际的数据数组*/
	        transient Object[] elementData; // non-private to simplify nested class access
	    
	        /* 集合长度成员变量*/
	        private int size;
构造函数
			 /*带有长度的集合初始化*/
	        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);
	            }
	        }
	    
	        /*无参构造,默认长度10 */
	        public ArrayList() {
	            this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
	        }
	    
	        /*Collection 集合构造方式,直接将集合转给数组,复制给全局保存数据数组*/
	        public ArrayList(Collection<? extends E> c) {
	            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);
	            } else {
	                // replace with empty array.
	                this.elementData = EMPTY_ELEMENTDATA;
	            }
	        }
集合扩容
			 /* 扩容方法,判断当前容量数据是否为默认长度数组,是0,否10,作用是传入小于默认容量的数字时,不进行扩容缩容*/
	        public void ensureCapacity(int minCapacity) {
	            int minExpand = (elementData != DEFAULTCAPACITY_EMPTY_ELEMENTDATA)
	                // any size if not default element table
	                ? 0
	                // larger than default for default empty table. It's already
	                // supposed to be at default size.
	                : DEFAULT_CAPACITY;
	    
	            if (minCapacity > minExpand) {
	                ensureExplicitCapacity(minCapacity);
	            }
	        }
	    
	        /*扩容,如果当前容量数据就是默认长度数组,则取传入长度数值与默认长度数据最大的长度,进行扩容.*/
	        private void ensureCapacityInternal(int minCapacity) {
	            if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
	                minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
	            }
	            ensureExplicitCapacity(minCapacity);
	        }
	    
	        /*扩容,包含记录集合容量变化次数操作(modCount++),传入长度超过当前容量长度进行扩容 */
	        private void ensureExplicitCapacity(int minCapacity) {
	            modCount++;

	            // overflow-conscious code
	            if (minCapacity - elementData.length > 0)
	                grow(minCapacity);
	        }
	    
	        /* 数租最大长度为2^31-9*/
	        private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
	    
	        /**
	         * 实际扩容方法,每次扩容为原来的1.5倍,如果扩容后长度还是小于需要扩容的长度,以实际长度扩容
	         * 实际扩容超过数租最大长度实际扩容为Integer.MAX_VALUE长度,然后复制到当前数据容量数组中,这个操作有 *可能引起虚拟机内存相关问题
	         */
	        private void grow(int minCapacity) {
	            // overflow-conscious code
	            int oldCapacity = elementData.length;
	            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);
	        }

	        /*超过默认数组最大长度,返回Integer.MAX_VALUE值*/
	        private static int hugeCapacity(int minCapacity) {
	            if (minCapacity < 0) // overflow
	                throw new OutOfMemoryError();
	            return (minCapacity > MAX_ARRAY_SIZE) ?
	                Integer.MAX_VALUE :
	                MAX_ARRAY_SIZE;
	        }
核心方法
	        /*将当前容量值设置为当前元素实际大小,size:元素实际大小,elementData.length当前容量值*/
	        public void trimToSize() {
	            modCount++;
	            if (size < elementData.length) {
	                elementData = (size == 0)
	                  ? EMPTY_ELEMENTDATA
	                  : Arrays.copyOf(elementData, size);
	            }
	        }
	    
	        /* 返回集合数据长度,注意不是容量长度, */
	        public int size() {
	            return size;
	        }
	    
	        /*判断是否为空,显示编码用长度和0进行判断也是可以的(注意空指针) */
	        public boolean isEmpty() {
	            return size == 0;
	        }
	    
	        /* 是否包含某元素,实际调用的是indexOf方法 */
	        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;
	        }
	    
	        /*返回某元素在集合中最后一个元素索引位置*/
	        public int lastIndexOf(Object o) {
	            if (o == null) {
	                for (int i = size-1; i >= 0; i--)
	                    if (elementData[i]==null)
	                        return i;
	            } else {
	                for (int i = size-1; i >= 0; i--)
	                    if (o.equals(elementData[i]))
	                        return i;
	            }
	            return -1;
	        }
	    
	        /*返回ArrayList的浅拷贝*/
	        public Object clone() {
	            try {
	                ArrayList<?> v = (ArrayList<?>) super.clone();
	                v.elementData = Arrays.copyOf(elementData, size);
	                v.modCount = 0;
	                return v;
	            } catch (CloneNotSupportedException e) {
	                // this shouldn't happen, since we are Cloneable
	                throw new InternalError(e);
	            }
	        }
	    
	        /*集合转数组,注意size数据实际数目*/
	        public Object[] toArray() {
	            return Arrays.copyOf(elementData, size);
	        }
	    
	        /*集合转指定类型数组*/
	        @SuppressWarnings("unchecked")
	        public <T> T[] toArray(T[] a) {
	            if (a.length < size)
	                // Make a new array of a's runtime type, but my contents:
	                return (T[]) Arrays.copyOf(elementData, size, a.getClass());
	            System.arraycopy(elementData, 0, a, 0, size);
	            if (a.length > size)
	                a[size] = null;
	            return a;
	        }
	    
	        /*获得当前索引对象,类中操作*/
	        @SuppressWarnings("unchecked")
	        E elementData(int index) {
	            return (E) elementData[index];
	        }
	    
	        /*获得某索引的对象,对外方法*/
	        public E get(int index) {
	            //判断是否索引越界(获取索引大于集合实际数据个数)
	            rangeCheck(index);
	    
	            return elementData(index);
	        }
	    
	        /*给某索引设置值*/
	        public E set(int index, E element) {
	            //判断时候索引越界(获取索引大于集合实际数据个数),注意:增加的话用add()方法,这里只能设置索引为0--size位置的值
	            rangeCheck(index);
	            //获取原来值
	            E oldValue = elementData(index);
	            //设置
	            elementData[index] = element;
	            //返回原来值
	            return oldValue;
	        }
	    
	        /* 
	        *向集合中添加元素,感觉add方法很耗性能,每次调用都会进行扩容判断,不够就进行扩容
	        *  所以创建集合对象时 可以预估长度就给上长度
			*/
	        public boolean add(E e) {
	            //扩容,保证有空间减价元素
	            ensureCapacityInternal(size + 1);  // Increments modCount!!
	            //设置值
	            elementData[size++] = e;
	            //返回状态
	            return true;
	        }
	    
	        /*想某个索引中添加元素,这种方法利用于创建是已经给了长度或者想0-9索引中添加元素*/
	        public void add(int index, E element) {
	            //判断索引是否合法
	            rangeCheckForAdd(index);
	            //判断是否需要扩容
	            ensureCapacityInternal(size + 1);  // Increments modCount!!
	            //复制元素
	            System.arraycopy(elementData, index, elementData, index + 1,
	                             size - index);
	            //设置
	            elementData[index] = element;
	            //个数值自增
	            size++;
	        }
	    
	        /*删除元素,返回要删除索引值*/
	        public E remove(int index) {
	            //索引合法判断
	            rangeCheck(index);
	            //集合数据数组结构变化次数加1
	            modCount++;
	            //获取原来值
	            E oldValue = elementData(index);
	            //复制值
	            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
	            //返回原来值
	            return oldValue;
	        }
	    
	       /*删除元素,返回删除成功与否状态,只删除第一个比配的元素 */
	        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
	        }
	    
	        /*集合清空*/
	        public void clear() {
	            modCount++;
	    
	            // clear to let GC do its work
	            for (int i = 0; i < size; i++)
	                elementData[i] = null;
	            size = 0;
	        }
	    
	        /*按照c的迭代器所返回的元素顺序,将c中的所有元素添加到此列表的尾部*/
	        public boolean addAll(Collection<? extends E> c) {
	            Object[] a = c.toArray();
	            int numNew = a.length;
	            ensureCapacityInternal(size + numNew);  // Increments modCount
	            System.arraycopy(a, 0, elementData, size, numNew);
	            size += numNew;
	            return numNew != 0;
	        }
	    
	        /*从指定位置index开始,将指定c中的所有元素插入到此列表中*/
	        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;
	            if (numMoved > 0)
	                 //先将ArrayList中从index开始的numMoved个元素移动到起始位置为index+numNew的后面去
	                System.arraycopy(elementData, index, elementData, index + numNew,
	                                 numMoved);
	             //再将c中的numNew个元素复制到起始位置为index的存储空间中去
	            System.arraycopy(a, 0, elementData, index, numNew);
	            size += numNew;
	            return numNew != 0;
	        }
	        
	         /*删除fromIndex到toIndex之间的全部元素 */
	        protected void removeRange(int fromIndex, int toIndex)
	        {
	            modCount++;
	            //numMoved为删除索引后面的元素个数
	            int numMoved = size - toIndex;  
	            //将删除索引后面的元素复制到以fromIndex为起始位置的存储空间中去
	            System.arraycopy(elementData, toIndex, elementData, fromIndex,numMoved);
	            int newSize = size - (toIndex-fromIndex);
	            //将ArrayList后面(toIndex-fromIndex)个元素置为null
	            for (int i = newSize; i < size; i++)
	            {
	                elementData[i] = null;
	            }
	            size = newSize;
	        }
	    
	        /* 检查索引是否越界 */
	        private void rangeCheck(int index) {
	            if (index >= size)
	                throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
	        }
	    
	        /*判断索引是否合法*/
	        private void rangeCheckForAdd(int index) {
	            if (index > size || index < 0)
	                throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
	        }
	    
	        /*拼接MSG*/
	        private String outOfBoundsMsg(int index) {
	            return "Index: "+index+", Size: "+size;
	        }
	    
	        /* 删除全部,删除ArrayList中包含在c中的元素*/
	        public boolean removeAll(Collection<?> c) {
	            //检查是否为空
	            Objects.requireNonNull(c);
	            //删除
	            return batchRemove(c, false);
	        }
	    
	        /*返回交集*/
	        public boolean retainAll(Collection<?> c) {
	            Objects.requireNonNull(c);
	            return batchRemove(c, true);
	        }
	        
	        /*删除方法*/
	        private boolean batchRemove(Collection<?> c, boolean complement) {
	            final Object[] elementData = this.elementData;
	            int r = 0, w = 0;
	            boolean modified = false;
	            try {
	                for (; r < size; r++)
	                    if (c.contains(elementData[r]) == complement)
	                        elementData[w++] = elementData[r];
	            } finally {
	                // Preserve behavioral compatibility with AbstractCollection,
	                // even if c.contains() throws.
	                if (r != size) {
	                    System.arraycopy(elementData, r,
	                                     elementData, w,
	                                     size - r);
	                    w += size - r;
	                }
	                if (w != size) {
	                    // clear to let GC do its work
	                    for (int i = w; i < size; i++)
	                        elementData[i] = null;
	                    modCount += size - w;
	                    size = w;
	                    modified = true;
	                }
	            }
	            return modified;
	        }
	    
	        /* 将ArrayList的“容量,所有的元素值”都写入到输出流中 */
	        private void writeObject(java.io.ObjectOutputStream s)
	            throws java.io.IOException{
	            // Write out element count, and any hidden stuff
	            int expectedModCount = modCount;
	            s.defaultWriteObject();
	    
	            //写入数组大小
	            s.writeInt(size);
	    
	            //写入所有数组的元素
	            for (int i=0; i<size; i++) {
	                s.writeObject(elementData[i]);
	            }
	            
	            if (modCount != expectedModCount) {
	                throw new ConcurrentModificationException();
	            }
	        }
	    
	        /* 先将ArrayList的“大小”读出,然后将“所有的元素值”读出 */
	        private void readObject(java.io.ObjectInputStream s)
	            throws java.io.IOException, ClassNotFoundException {
	            elementData = EMPTY_ELEMENTDATA;
	    
	            // Read in size, and any hidden stuff
	            s.defaultReadObject();
	    
	            // Read in capacity
	            s.readInt(); // ignored
	    
	            if (size > 0) {
	                // be like clone(), allocate array based upon size not capacity
	                ensureCapacityInternal(size);
	    
	                Object[] a = elementData;
	                // Read in all elements in the proper order.
	                for (int i=0; i<size; i++) {
	                    a[i] = s.readObject();
	                }
	            }
	        }
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Starry-Leo

帮到了您,有闲钱,再打赏哦~

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值