源码解读--ArrayList

本文深入解析了Java中ArrayList的工作原理,包括初始化、添加、获取和删除等操作的实现细节,并探讨了其内部扩容机制和线程安全性问题。

对于开发人员来说,用的最多的就是数组,链表,Map和List,之前我写过一篇HashMap的源码解读,今天就来简单说说ArrayList的源码。java源码系列

一.首先看看她的初始化方法:

第①种

public ArrayList() {  //无参的构造器,初始值是一个默认的空  DEFAULTCAPACITY_EMPTY_ELEMENTDATA ={}
    this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;}
第②种
public ArrayList(Collection<? extends E> c) {  
    elementData = c.toArray();  
    if ((size = elementData.length) != 0) {  //如果值不为空
        // c.toArray 可能返回的不是 Object[] 
        if (elementData.getClass() != Object[].class)  //
            elementData = Arrays.copyOf(elementData, size, Object[].class);
    } else {
        // 如果为空无赋值空对象
        this.elementData = EMPTY_ELEMENTDATA;
    }
}

第③种

public ArrayList(int initialCapacity) {  //指定初始大小
    if (initialCapacity > 0) {
        this.elementData = new Object[initialCapacity];  //初始化对象数组,指定数组的大小为初始值
    } else if (initialCapacity == 0) {
        this.elementData = EMPTY_ELEMENTDATA;
    } else {  //若果initialCapcity<0要抛出异常
        throw new IllegalArgumentException("Illegal Capacity: "+
                                           initialCapacity);
    }
}

二. 添加:

public boolean add(E e) {
    ensureCapacityInternal(size + 1);  // 判断是否需要扩容
    elementData[size++] = e;  //添加一个元素
    return true;
}
private void ensureCapacityInternal(int minCapacity) {  
    if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {  //如果为空对象,
        minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);  //minCapacity为0和DEFULT_CAPACITY(10)取最大值为10 
    }

    ensureExplicitCapacity(minCapacity);   //校验容量
}
private void ensureExplicitCapacity(int minCapacity) {
    modCount++;  //修改的值加1

    // 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);  //扩容1.5倍
    if (newCapacity - minCapacity < 0)  //一般来说这里不会小于0
        newCapacity = minCapacity;    
    if (newCapacity - MAX_ARRAY_SIZE > 0) //大于最大值,要进一步判断
        newCapacity = hugeCapacity(minCapacity);
    elementData = Arrays.copyOf(elementData, newCapacity);  //用Arrays.copyOf赋值数组
}
private static int hugeCapacity(int minCapacity) {
    if (minCapacity < 0) // overflow  多线程修改这个list的长度小于0,要报错
        throw new OutOfMemoryError();
    return (minCapacity > MAX_ARRAY_SIZE) ?
        Integer.MAX_VALUE :
        MAX_ARRAY_SIZE;
}

到此,list的添加完毕,总结如下:

1.如果没有指定list的长度,初始一个空的数组

2.添加值的时候,list长度大于当前容量,就扩展1.5倍(默认长度是10),否则就正常添加

三. 获取值

public E get(int index) {
    rangeCheck(index);  //校验一下索引值

    return elementData(index);
}
private void rangeCheck(int index) {  //如果索引大于list的长度 抛出异常
    if (index >= size)
        throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}
E elementData(int index) {  //获取索引值
    return (E) elementData[index];
}

四.删除值

public E remove(int index) {
    rangeCheck(index);  //校验索引
    modCount++;  //修改记录数加1
    E oldValue = elementData(index);  //获取到索引的值
    int numMoved = size - index - 1;
    if (numMoved > 0)
        System.arraycopy(elementData, index+1, elementData, index,numMoved);  //将获取的index位置值扣掉,后面的值,复制到index位置
    elementData[--size] = null; // 将索引值赋值为空,便于gc
    return oldValue;
}
public static native void arraycopy(Object src,  int  srcPos, //src 源数组   srcPos 原数组要赋值的起始位置
                                    Object dest, int destPos,  // dest 目标数组   destPost 目标数组放置的起始位置
                                    int length);  //lenth 复制的长度

到此,ArrayList增删查就完成了,不过里面有几点需要注意一下。

1.ArrayList初始化的时候,默认值是10,有可能就尽量执行list的大小,因为每次扩容都是1.5倍,长度越大,浪费越大。

2.ArrayList是线程不安全的,注意多线程问题。



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值