ArrayList源码分析

ArrayList 源码解析

基于jdk1.7

成员变量

 private static final int DEFAULT_CAPACITY = 10;  //默认初始容量
 private static final Object[] EMPTY_ELEMENTDATA = {};	//空数组
 private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
 transient Object[] elementData;	 //数组,存储数据
 private int size;	//ArrayList的长度,小于或者等于elementData的长度
 protected transient int modCount = 0; // 列表被改变的次数
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8; //默认数组最大大小,实际可为Integer.MAX_VALUE

构造函数

  1. 无参构造函数
    //默认创建空数组; java1.7之后,数组扩容在add方法里面
    public ArrayList() {
            this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
    }
    
  2. 有参构造函数
//initialCapacity 初始化数组长度
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);
        }
    }
//接收集合对象
public ArrayList(Collection<? extends E> c) {
        elementData = c.toArray();
        if ((size = elementData.length) != 0) {
            // c.toArray 可能不会返回 Object[] (see 6260652)
            if (elementData.getClass() != Object[].class)
                //扩容:将旧数组,从位置0开始copy,如果size>旧数组的长度,则保留数组默认值
                //int[] a =[1,2,3,4,5]--->int[] b =[1,2,3,4,5,0,0,0,0,0]
                // b = Arrays.copyOf(a, 10);
                elementData = Arrays.copyOf(elementData, size, Object[].class);
        } else {
            //null
            this.elementData = EMPTY_ELEMENTDATA;
        }
    }

常用方法

  1. 
    public boolean add(E e) {
        ensureCapacityInternal(size + 1);  // 扩容:(size + 1)防止出现初始容量为1,扩容后容量还是为1的情况(此情况是由于Arraylist按照1.5倍导致)
        elementData[size++] = e;
        return true;
    }
    
     public void add(int index, E element) {
         	//检查角标是否越界
            rangeCheckForAdd(index);
    
            ensureCapacityInternal(size + 1);  // 扩容
         	// public static native void arraycopy(Object src,  int  srcPos,Object dest, int destPos,int length);
    	    // src:源数组;
            //  srcPos:源数组要复制的起始位置;
            //  dest:目的数组;
            //  destPos:目的数组放置的起始位置;	length:复制的长度。
            //	理解:从src数组的srcPos位置开始复制length个元素,将复制到的元素从dest数组的destPos位置依次放置
            //  实现原理: 先生成一个长度为length的临时数组,将fun数组中srcPos到srcPos+length-1之间的数据拷贝到临时数组中,再执行System.arraycopy(临时数组,0,fun,3,3).
         	// 例:int[] arr = {1,2,3,4,5,6}; System.arraycopy(arr,2,arr,4,2);-->[1,2,3,4,3,4]
            System.arraycopy(elementData, index, elementData, index + 1,size - index);
            elementData[index] = element;
            size++;
     }
    
    
    //扩容关键代码
    
    private void ensureCapacityInternal(int minCapacity) {
            ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
    }
    
    private static int calculateCapacity(Object[] elementData, int minCapacity) {
        	//判断是否为空数组
            if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
                //比较minCapacity和默认容量大小,取较大值
                return Math.max(DEFAULT_CAPACITY, minCapacity);
            }
            return minCapacity;
    }
    
    private void ensureExplicitCapacity(int minCapacity) {
        modCount++;
        // 防止溢出
        if (minCapacity - elementData.length > 0)
            grow(minCapacity);
    }
    
    private void grow(int minCapacity) {
            // overflow-conscious code
            int oldCapacity = elementData.length;	//原数组长度
            int newCapacity = oldCapacity + (oldCapacity >> 1);	//数组长度+数组长度×0.5
        	//判断数组扩容后的长度是否小于实际需要的长度(minCapacity新的元素的位置)
            if (newCapacity - minCapacity < 0)
                newCapacity = minCapacity;
        	//判断是否超过数组最大大小
            if (newCapacity - MAX_ARRAY_SIZE > 0)
                newCapacity = hugeCapacity(minCapacity);
            // 扩容
            elementData = Arrays.copyOf(elementData, newCapacity);
    }
    
    //数组最大容量为Integer的最大值
    private static int hugeCapacity(int minCapacity) {
            if (minCapacity < 0) // overflow
                throw new OutOfMemoryError();
            return (minCapacity > MAX_ARRAY_SIZE) ?Integer.MAX_VALUE :MAX_ARRAY_SIZE;
    }
    
    //检查角标是否越界
     private void rangeCheckForAdd(int index) {
            if (index > size || index < 0)
                throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
     }
    
  2. public E remove(int index) {
            rangeCheck(index);	//检查角标是否越界
    
            modCount++;
            E oldValue = elementData(index);	//旧元素
    
            int numMoved = size - index - 1;	//需要往前移动的元素的个数
            if (numMoved > 0)	//判断要移除的是否为最后一个元素
                //数组内部位置在index之后的元素向前移动
                System.arraycopy(elementData, index+1, elementData, index,numMoved);
            elementData[--size] = null; // 将最后一个元素置空,让GC回收
    
            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++)
                    //调用对象自己的equals进行比较
                    if (o.equals(elementData[index])) {
                        fastRemove(index);
                        return true;
                    }
            }
            return false;
     }
    
    //和remove(int index)类似
    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
     }
    
  3. public E set(int index, E element) {
            rangeCheck(index);
            E oldValue = elementData(index);	//获取旧元素
            elementData[index] = element;	//赋值
            return oldValue;
    }
    
    @SuppressWarnings("unchecked")
    E elementData(int index) {
        //elementData 元素默认为Object此处直接进行强制转换
        return (E) elementData[index];
    }
    
  4. public E get(int index) {
            rangeCheck(index);
    
            return elementData(index);
    }
    

重要点

  1. 通过无参构造函数创建ArrayList时,数组默认长度为0,调用add方法后会进行扩容,默认初始大小为10,每次扩容1.5倍

  2. 扩容关键函数:

    • System.arraycopy(): 该方法用了 native 关键字,说明调用的是其他语言写的底层函数。 需要目标数组,将原数组拷贝到你自己定义的数组里,而且可以选择拷贝的起点和长度以及放入新数组中的位置

      
      
    • Arrays.copyOf(): copyOf() 是系统自动在内部新建一个数组,调用 arraycopy() 将 original 内容复制到 copy 中去,并且长度为 newLength。返回 copy; 即将原数组拷贝到一个长度为 newLength 的新数组中,并返回该数组。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值