【ArrayList类中基础方法逻辑1】

主要成员变量

private static final int DEFAULT_CAPACITY = 10;//数组默认初始容量
private static final Object[] EMPTY_ELEMENTDATA = {};//定义一个空的数组实例以供其他需要用到空数组的地方调用 
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};//定义一个空数组,跟EMPTY_ELEMENTDATA区别就是这个空数组是用来判断ArrayList第一添加数据的时候要扩容多少。默认的构造器情况下返回这个空数组 
transient Object[] elementData;//在集合中数据存储的地方,它的容量就是这个数组的长度
private int size;//当前数组的长度

一、构造方法

ArrayList构造方法有三种

无参构造:
    将初始化的空的数组赋值给elementData,就是初始化一个空的集合。该方法的官方注释:Constructs an empty list 
	with an initial capacity of ten.(初始化一个容量为10的空列表),个人理解是在list的add()方法中初始化为10的。
public ArrayList() {
    this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
有参构造1
	入参为列表的初始化长度。
	入参不能为负数,为负数报错。
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);
        }
    }
有参构造2:
	入参为一个集合;
	其中elementData.getClass() != Object[].class,为什么要做如此判断,详见:https://blog.csdn.net/weixin_46122805/article/details/124756682
    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;
        }
    }

二、增删改以及各种功能性方法

在分析一部分方法的同时,会穿插着另一些功能方法

1、新增元素add()

(1)单参add()

    public boolean add(E e) {
        ensureCapacityInternal(size + 1);  // Increments modCount!!
        elementData[size++] = e;
        return true;
    }
我们看到第一行代码调用了ensureCapacityInternal(),这个方法是要保证存储数据的空间,以下都是扩容相关的方法,看源码:
	//保证内部容量
	//在这个方法中,又调用了两个方法,是扩容逻辑一系列的方法
    private void ensureCapacityInternal(int minCapacity) {
          ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
    }
	//计算容量
    //该方法判断了当前elementData是否为空,以及为空不为空情况取得扩容数值的大小
    //在这个方法中可以看到当elementData为空,第一次添加数据的时候会扩容到10,DEFAULT_CAPACITY的默认值是10
    private static int calculateCapacity(Object[] elementData, int minCapacity) {
        if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
            return Math.max(DEFAULT_CAPACITY, minCapacity);
        }
        return minCapacity;
    }
    //确定明确容量
    private void ensureExplicitCapacity(int minCapacity) {
    	//modCount这个参数是AbstractList类中的,当集合的结构被改变,增删之类的,modCount会增加。该特性主要是防止在迭代时被修改,造成不确定性问题
        modCount++;
        // overflow-conscious code
        //如果新增加的size大于数组的长度,就需要扩容,调用grow()
        if (minCapacity - elementData.length > 0)
            grow(minCapacity);
    }
//当集合中存储空间不足时,调用grow()方法扩容,“oldCapacity + (oldCapacity >> 1)”决定了最小扩容量为原本长度的1.5倍;"newCapacity - 
MAX_ARRAY_SIZE > 0"当扩容后的长度大于ArrayList的默认最大长度时,就调用hugeCapacity()方法,该方法决定了集合的扩容最大值为
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:
        //扩容的过程是一个复制的过程,底层使用了System.arraycopy()方法,将旧数组的数据复制给新数组
        elementData = Arrays.copyOf(elementData, newCapacity);
    }
    private static int hugeCapacity(int minCapacity) {
        if (minCapacity < 0) // overflow
            throw new OutOfMemoryError();
        return (minCapacity > MAX_ARRAY_SIZE) ?
            Integer.MAX_VALUE :
            MAX_ARRAY_SIZE;
    }

(2)多参add()

    public void add(int index, E element) {
    //判断index是否符合数组范围,如果大于或小于范围,报数组下标越界
        rangeCheckForAdd(index);

        ensureCapacityInternal(size + 1);  // Increments modCount!!
        System.arraycopy(elementData, index, elementData, index + 1,size - index);
        elementData[index] = element;
        size++;
    }
    private void rangeCheckForAdd(int index) {
        if (index > size || index < 0)
            throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
    }

(3)单参addAll()

这个接口很好理解,这里对addAll()方法中的System.arraycopy()的参数做一个解释:
System.arraycopy(a,aindex,b,bindex,length);
将a中的数据从aindex的位置复制到b,存放的位置从bindex开始,length代表复制a中的几个元素
    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;
    }

(4)多参addAll()

    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);
        size += numNew;
        return numNew != 0;
    }
只要能够理解上边的内容,remove()\get()这些方法只要就也没问题
下一篇接着学习ArrayList的方法

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值