Java学习笔记十八-ArrayList源码分析

最近学习了ArrayList类,自己试着编写了其中常用的函数,发现和源码差的不是一点点...

在类的属性中,定义了size属性,记录数组的长度。以及elementData空数组

/*    获得数组的长度  */

public int size() {
        return size;
    }

/*   判断数组是否为空  */

public boolean isEmpty() {
        return size == 0;
    }

/*   获得元素的索引位  */

public int indexOf(Object o) {                      //返回传入参数的索引位
        if (o == null) {                            //当传入参数为空时,遍历数组是否有元素为空
            for (int i = 0; i < size; i++)          //防止equals函数报错
                if (elementData[i]==null)
                    return i;                       //返回位置
        } else {                                    //传入参数不为空时遍历数组,找到匹配元素
            for (int i = 0; i < size; i++)
                if (o.equals(elementData[i]))
                    return i;                       //相等则返回位置
        }
        return -1;                                  //找不到则返回-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;
    }

/*  返回指定索引位的元素   */

 public E get(int index) {                       //利用了泛型,输入索引位返回值
        rangeCheck(index);                       //该函数用来判断是否下标越界
        return elementData(index);               //下标不越界则返回值(该函数将取到的数据强制转化为泛型)
 }
private void rangeCheck(int index) {             //如果参数大于数组的大小,抛出异常
        if (index >= size)
            throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
    }
E elementData(int index) {
        return (E) elementData[index];
    }

/*   更改指定索引位的数据,并返回原值  */

public E set(int index, E element) {               //设置索引位index的数据值为element
        rangeCheck(index);                               //检查索引是否越界

        E oldValue = elementData(index);            //将原值强制转换为泛型
        elementData[index] = element;               //赋值
        return oldValue;                                     //返回原值
    }

/*   向数组尾添加元素  */

public boolean add(E e) {
        ensureCapacityInternal(size + 1);   // Increments modCount!!  将最小容量设置为当前长度加1,便于之后扩容
        elementData[size++] = e;            //扩容之后将元素添加到末尾即可
        return true;                        //返回添加成功
    }
private void ensureCapacityInternal(int minCapacity) {                     //确保内部容量
        if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {            //如果数组现在是空的话
            minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);         //最小值为默认容量和最小容量的最大值(保证数组至少是默认容量大小)
        }                                                                  //minCapacity表示所需的最小容量

        ensureExplicitCapacity(minCapacity);
    }
private void ensureExplicitCapacity(int minCapacity) {
        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;
        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);     //将旧数组改变为新容量大小的数组,即实现扩容
    }
private static int hugeCapacity(int minCapacity) {                //设置最大容量函数
        if (minCapacity < 0) // overflow                          //如果最小容量小于0,抛出溢出错误
            throw new OutOfMemoryError();
        return (minCapacity > MAX_ARRAY_SIZE) ?                   //如果最小容量大于最大数组容量,则返回整数的最大值
            Integer.MAX_VALUE :                                   //否则返回设定的最大数组容量
            MAX_ARRAY_SIZE;
    }

/*  向指定索引位添加元素  */

public void add(int index, E element) {
        rangeCheckForAdd(index);                                        //为了数组添加的越界检查
 
        ensureCapacityInternal(size + 1);  // Increments modCount!!  与上一个add相同,数组扩容
        System.arraycopy(elementData, index, elementData, index + 1,size - index);   //将索引位前后分别复制到一个新数组里,留下索引位空位
        elementData[index] = element;                                                //向索引位加入元素
        size++;
    }
 private void rangeCheckForAdd(int index) {
        if (index > size || index < 0)                                  //如果索引位大于数组长度或者小于0,抛出索引越界异常
            throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
    }

/*   移除索引位的元素并返回   */

public E remove(int index) {
        rangeCheck(index);                     //检查输入索引位是否越界(前面写过了这个函数)

        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 清空最后一个空位,让GC回收

        return oldValue;
    }

/*  移除数组里的某个元素     removeAll方法需要传入一个集合对象  */

public boolean remove(Object o) {
        if (o == null) {                                       //如果要移除的数据为空的话
            for (int index = 0; index < size; index++)         //遍历数组,如果有为空的元素,则移除该元素
                if (elementData[index] == null) {             
                    fastRemove(index);                         //与上remove操作类似
                    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++)           //遍历数组均置为空,让GC回收
            elementData[i] = null;

        size = 0;                                //数组尺寸设为0
    }

/*   添加集合中的全部元素到数组尾   */

  public boolean addAll(Collection<? extends E> c) {               //泛型
        Object[] a = c.toArray();                                  //将集合c转换为数组a
        int numNew = a.length;                                     //获得a的长度
        ensureCapacityInternal(size + numNew);                     // Increments modCount 将数组长度至少设置为size+numNew便于扩容 
        System.arraycopy(a, 0, elementData, size, numNew);         //将一个新长度的数组赋给原数组
        size += numNew;                                            //数组有效尺寸增加
        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;                                   //获得需要移动的数据个数
        if (numMoved > 0) 
            System.arraycopy(elementData, index, elementData, index + numNew,      //重新获得数组,留出中间的空位
                             numMoved);

        System.arraycopy(a, 0, elementData, index, numNew);             //将a数组赋值到空位中
        size += numNew;                                                 //数组有效位数增加
        return numNew != 0;
    }

/*  将数组两个索引位之间的数据取出为List形式    

     注意:subList包前不包后,截取的是fromIndex到toIndex之前的部分

  */

public List<E> subList(int fromIndex, int toIndex) {
        subListRangeCheck(fromIndex, toIndex, size);                     //检查子链的两个索引位是否符合要求
        return new SubList(this, 0, fromIndex, toIndex);                 //返回从fromIndex到toIndex的子链  SubList是一个内部类
    }
static void subListRangeCheck(int fromIndex, int toIndex, int size) {
        if (fromIndex < 0)                                                       //第一个索引位小于0则抛出异常
            throw new IndexOutOfBoundsException("fromIndex = " + fromIndex);
        if (toIndex > size)                                                      //第二个索引位大于数组尺寸则抛出异常
            throw new IndexOutOfBoundsException("toIndex = " + toIndex);
        if (fromIndex > toIndex)                                                 //第一个索引位大于第二个索引位抛出异常
            throw new IllegalArgumentException("fromIndex(" + fromIndex +
                                               ") > toIndex(" + toIndex + ")");
    }

/*

  *在这个函数中,操作的还是原来的集合,即对截取出来的子集进行处理时,原集合也会改变。虽然子集

  *与子集的地址不是同一个,但是指向的是同一个对象

  */

猜你喜欢

转载自blog.csdn.net/weixin_40373090/article/details/80779959