ArrayList源码分析

本文详细解读ArrayList的构造函数,包括无参、指定初始容量及从Collection创建,以及add方法的使用,涉及容量调整、get/set/remove操作。讨论了线程安全性问题和工作原理,对比其他数据结构如数组。
摘要由CSDN通过智能技术生成

ArrayList

1.构造函数

1.1无参构造函数:
//无参,构造一个初始容量为10的空列表
    public ArrayList() {
        this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA; 
    }

给出默认值为空,初始容量为10的空列表(调用add时候才能体现)

1.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);
        }
    }

直接给了初始容量initialCapacity:

大于0:将带有固定容量的数组赋给该数组集合

等于0:将{}赋给集合

小于0:抛出异常

1.3构造一个包含指定元素的列表
 public ArrayList(Collection<? extends E> c) {
        elementData = c.toArray();         //把集合转换为Object[]数组(来自于Collection)
        if ((size = elementData.length) != 0) {   //把数组长度赋给当前的ArrayList集合的size,并判断是否为0
            // c.toArray might (incorrectly) not return Object[] (see 6260652)
            if (elementData.getClass() != Object[].class)   //toArray返回的不一定时Object类型,得重新转换为Object类型
                elementData = Arrays.copyOf(elementData, size, Object[].class);
        } else {
            // replace with empty array.
            this.elementData = EMPTY_ELEMENTDATA;  //如果为0:将element替换为空数组
        }

    }

2.增add()

2.1add(E e)
public boolean add(E e) {       //boolean型
    //1.加入元素前,检查数组容量是否足够
    ensureCapacityInternal(size + 1);  // Increments modCount!!
    //首先会调用 ensureCapacityInternal(size + 1),其作用为保证数组的容量始终够用,否则就扩容
    //得到确切容量值
    elementData[size++] = e;  //在size后添加元素
    return true;  //添加成功
}

1.加入元素之前,检查数组容量是否足够

2.首先会调用 ensureCapacityInternal(size + 1),其作用为保证数组的容量始终够用,其中 size是elementData数组中元组的个数,初始为0

3.如果添加元素后大于当前数组长度,调用扩容函数grow(minCapacity)

4.扩容函数会在下面详细说明

2.2add(int index,E elsement)
public void add(int index, E element) {     //void
    rangeCheckForAdd(index);  //index > size || index < 0
    //检查下标值是否在数组容量范围
    ensureCapacityInternal(size + 1);  // Increments modCount!!
    //得到确切容量值
    System.arraycopy(elementData, index, elementData, index + 1,
                     size - index);
    //将elementData从索引为index的元素开始,复制到数组elementData里的索引为index+1的位置,复制元素为size-index个
    //总之就是将elementData插入index位置,之后的元素往后移一位
    elementData[index] = element;
    size++; //计数
}

3.扩容函数grow(int minCapacity)

private void grow(int minCapacity) {   //容量要保证能装下mincapacity所指定的容量大小
    // overflow-conscious code
    int oldCapacity = elementData.length; //把数组的长度赋给oldCapacity
    int newCapacity = oldCapacity + (oldCapacity >> 1);  //加上自己本身一半
    //新的数组容量=老的数组长度的1.5倍。

    if (newCapacity - minCapacity < 0)   //如果新的数组容量newCapacity小于传入的参数要求的最小容量minCapacity
        newCapacity = minCapacity;//那么新的数组容量以传入的容量参数为准,够用就行。
    if (newCapacity - MAX_ARRAY_SIZE > 0)  //大于2^31-1-8时:
        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)
        throw new OutOfMemoryError();
    return (minCapacity > MAX_ARRAY_SIZE) ?
        Integer.MAX_VALUE :  //如果还大的话就只能取2^31-1了
        MAX_ARRAY_SIZE;  //否则
}

先将容量扩充至当前容量的1.5倍,若还不够,则将容量扩充至当前需要的数量,再不够就扩容到最大

4.查get(int)

public E get(int index) {
    rangeCheck(index);  
    //范围检查,注意,这里是index不能等于size,添加函数可以等于;还有一般也没有说取负数个的,所以也没有负数限制了吧
    return elementData(index);   //返回得到index位置的元素值
}

5.改set(int E)

public E set(int index, E element) {
    rangeCheck(index);  //同样是范围检查,其实看到上面就在想,为啥不加一个>=0的范围呢,否则小于0时 最后返回的是啥呢

    E oldValue = elementData(index);   //存放原来位置上的元素
    elementData[index] = element;   //给该位置赋新值
    return oldValue;   //返回原来的元素值
}

6.删

6.1remove(int)
public E remove(int index) {
    rangeCheck(index);      //index >= size

    modCount++;    //记录更改次数
    E oldValue = elementData(index);    //存放元素

    int numMoved = size - index - 1;  //移除元素后,其它元素需要移动numMoved个
    if (numMoved > 0)
        System.arraycopy(elementData, index+1, elementData, index,
                         numMoved);
    //相当于数组复制,将elementData从索引为index+1位置复制到数组elementData索引为index位置,复制元素为size-index-1个
    elementData[--size] = null; // clear to let GC do its work
    //先给最末尾元素赋空值,然后让GC来清理
    return oldValue;   //返回原来的值
}
6.2remove(Object) (boolean类型)

和第一个删除函数差不多,找到相同的值然后调用了fastRemove函数,

里面最主要的还是包含了arraycopy函数,进行数组移动复制。

需要注意的是!!!:当对象为null时,不能调用equal进行比较,需要用==比较,null和其他object类不是相同对象

,==比较的时引用,而equal比较的是两个对象

采用什么数据结构?

数组

如何实现的?为什么这么实现?

线程是否安全?

线程不安全

说一下工作原理?

说一下每个函数的执行过程?

与其他数据结构的区别?

个人源码分析,有错勿怪,指出虚心改正

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值