ArrayList源码解读二之add、set、get、remove

ArrayList源码解读二之add、set、get、remove

在看add、set源码之前,我们先看几个重要的函数,add、set、remove、get都会调用它。

private static int calculateCapacity(Object[] elementData, int minCapacity) {//获取数组大小
    if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA)           
    {//创建无参构造器时候会把DEFAULTCAPACITY_EMPTY_ELEMENTDATA指向elementData
        return Math.max(DEFAULT_CAPACITY, minCapacity);
    }//当创建无参构造时候才会有用到,默认值为10 
    return minCapacity;
}
private void ensureCapacityInternal(int minCapacity) {//add、set、remove、get先都会调用此方法
    ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
}//minCapacity是添加元素后数组大小
private void ensureExplicitCapacity(int minCapacity) {
    modCount++;//记录修改次数
    if (minCapacity - elementData.length > 0)//当添加元素后数组大小大于原来数组大小长度
        grow(minCapacity);//扩容函数
}
private void grow(int minCapacity) {
    int oldCapacity = elementData.length;
    int newCapacity = oldCapacity + (oldCapacity >> 1);//扩容1.5倍
    if (newCapacity - minCapacity < 0)//当添加元素后数组大于扩容后的倍数时
        newCapacity = minCapacity;
    if (newCapacity - MAX_ARRAY_SIZE > 0)//当数组远远大于Array规范长度时候
        newCapacity = hugeCapacity(minCapacity);
    elementData = Arrays.copyOf(elementData, newCapacity);//复制
}
  • 一般情况进行扩容是1.5倍。
  • 特殊情况:添加的元素后的数量远超过扩容1.5倍的值时,会扩容添加元素的数量。
    ( 比如说:第一个ArrayList大小是10 第二个ArrayList大小为30 进行addALL函数操作的时候minCapacity的大小是30 远远超过扩容1.5倍后的数量)
    注意!!!许多在讲arrayList扩容机制的时候只会说1.5倍 而不说特殊情况。

看懂这些方法后接下来到add、set、get、remove函数就容易了。
(相比add方法)set、get、remove函数可以选择性看!!!!!!!!

1.ArrayList中的add函数。

add函数

public boolean add(E e) {
    ensureCapacityInternal(size + 1); //进行扩容机制
    elementData[size++] = e;//进行赋值
    return true;
}
public void add(int index, E element) {
    rangeCheckForAdd(index);
    ensureCapacityInternal(size + 1);
    System.arraycopy(elementData, index, elementData, index + 1,size - index);
    elementData[index] = element;
    size++;
}

add 2个方法基本操作差不多

  1. rangeCheckForAdd是判断index是否超过elementData的大小,是则抛出越界异常。
  2. ensureCapacityInternal是上面提到判断调用的函数,最主要是进行扩容机制。
  3. System.arraycopy是为直接原数组index后面的值往后移一位如图显示。
    在这里插入图片描述
  4. 赋值。
  5. 记录元素数量,并且+1。

2.ArrayList中的set函数。

set函数

public E set(int index, E element) {
    rangeCheck(index);//是否检查越界
    E oldValue = elementData(index);
    elementData[index] = element;
    return oldValue;
}
  • 首先获取到elementData的index旧元素
  • 将新的element值赋予index
  • 返回给OldValue**

3.ArrayList中的get函数。

get函数

public E get(int index) {
    rangeCheck(index);
    return elementData(index);
}

1. 获取到element(index)的位置元素返回。

4.ArrayList中的remove函数。

remove函数

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;
    return oldValue;
}
  • 首先获取到elementData的index旧元素
  • 获取index后面需要移动的位置
  • System.arraycopy进行移动(与addAll差不多)
  • 对空出来的元素进行赋值null值
  • 返回旧值

结论:

  • 无参构造在第一次添加元素时候进行扩容后容量会是10。
  • 扩容机制一般情况是1.5倍,特殊情况(添加元素大于扩容1.5倍的时候)是扩容为添加元素本身大小。
  • 指定位置index操作元素时候都会进行越界检查、并且会对数组进行移动操作。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: ArrayListJava语言中的一种数据结构,它是基于动态数组实现的,可以根据需要自动扩容。 下面是ArrayList源码: ```java public class ArrayList<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, java.io.Serializable { private static final long serialVersionUID = 8683452581122892189L; private transient Object[] elementData; private int size; public ArrayList(int initialCapacity) { super(); if (initialCapacity < 0) throw new IllegalArgumentException("Illegal Capacity: "+ initialCapacity); this.elementData = new Object[initialCapacity]; } public ArrayList() { this(10); } public boolean add(E e) { ensureCapacityInternal(size + 1); elementData[size++] = e; return true; } public E get(int index) { rangeCheck(index); return elementData(index); } public E set(int index, E element) { rangeCheck(index); E oldValue = elementData(index); elementData[index] = element; return oldValue; } public int size() { return size; } private void rangeCheck(int index) { if (index >= size) throw new IndexOutOfBoundsException(outOfBoundsMsg(index)); } private String outOfBoundsMsg(int index) { return "Index: "+index+", Size: "+size; } } ``` 其中,ArrayList的实现是通过一个Object类型的数组来存储数据,当数组空间不足时会自动进行扩容。同时,ArrayList实现了List和RandomAccess接口,因此可以像数组一样进行随机访问,并且可以使用List的各种方法来操作数据。除此之外,ArrayList还支持序列化和克隆。 ### 回答2: ArrayListJava中常见的集合类之一,它是基于数组的动态数组实现。其源码位于`java.util`包下。 在ArrayList源码中,我们可以看到它的核心组成部分是一个Object类型的数组elementData来存储元素。当我们向ArrayList中添加元素时,它会根据需要动态调整数组的大小,并将元素添加到数组的末尾。 除了存储元素的数组外,ArrayList还包含一个整型的size用于记录实际存储的元素个数。通过size,ArrayList可以方便地管理当前存储的元素数量。 ArrayList源码中还包含了一系列常用的方法,用于对集合进行增删改查等操作。例如,add方法用于向ArrayList末尾添加元素,remove方法用于删除指定位置的元素,get方法用于获取指定位置的元素,等等。 在ArrayList源码中,还有一些涉及到数组扩容和复制的实现细节,以保证ArrayList的存储和访问效率。当ArrayList需要扩容时,会调用Arrays.copyOf方法来创建一个新的更大的数组,并将原数组中的元素复制到新数组中。 总的来说,ArrayList源码主要涉及到动态数组的实现细节,以及一系列常用的方法。它的设计和实现使得我们能够方便地使用和管理多个元素,提高了集合的灵活性和效率。 ### 回答3: ArrayListJava中的一种动态数组,是List接口的可调整大小的数组实现。它可以根据需要自动增长和缩减,提供了更灵活的数据存储方式。 ArrayList源码主要包括以下几个关键的部分: 1. 实现了List接口:ArrayList类实现了List接口,包括了List接口中定义的常规方法,如添加、删除、查找、修改元素等操作。 2. 内部数组:ArrayList使用一个内部数组data[]来存储元素,这个数组是动态的,可以根据需要自动扩容和缩容。 3. 扩容机制:当需要添加元素时,如果当前数组已满,ArrayList会创建一个更大的新数组,并将原数组的内容复制到新数组中。这种机制保证了数组的容量始终能够满足需求,并避免了频繁的元素搬迁。 4. 索引、增删改查方法:ArrayList提供了一系列方法来对元素进行操作,比如get(index)获取指定位置的元素,add(element)在末尾添加元素,remove(index)删除指定位置的元素,set(index, element)修改指定位置的元素等。 5. 其他方法:ArrayList还提供了其他一些方法,如size()返回元素个数,isEmpty()判断是否为空,contains()判断是否包含某个元素等。 6. 实现了序列化接口:ArrayList实现了Serializable接口,可以进行序列化和反序列化,可以在不同应用之间传递。 总之,ArrayList源码实现了动态可调整大小的数组,提供了一系列方便的方法来操作元素,增加了灵活性和便捷性。通过扩容机制,可以充分利用内存,避免频繁地进行数组复制。ArrayListJava集合中常用的数据结构之一,适合于需要频繁读取和修改元素的场景。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值