首页 > 试题广场 >

说一说ArrayList的实现原理

[问答题]

说一说ArrayList的实现原理

推荐

得分点

​ 数组实现、默认容量为10、每次扩容1.5倍

参考答案

标准回答

​ ArrayList是基于数组实现的,它的内部封装了一个Object[]数组。

​ 通过默认构造器创建容器时,该数组先被初始化为空数组,之后在首次添加数据时再将其初始化成长度为10的数组。我们也可以使用有参构造器来创建容器,并通过参数来显式指定数组的容量,届时该数组被初始化为指定容量的数组。

​ 如果向ArrayList中添加数据会造成超出数组长度限制,则会触发自动扩容,然后再添加数据。扩容就是数组拷贝,将旧数组中的数据拷贝到新数组里,而新数组的长度为原来长度的1.5倍。

​ ArrayList支持缩容,但不会自动缩容,即便是ArrayList中只剩下少量数据时也不会主动缩容。如果我们希望缩减ArrayList的容量,则需要自己调用它的trimToSize()方法,届时数组将按照元素的实际个数进行缩减。

加分回答

​ Set、List、Queue都是Collection的子接口,它们都继承了父接口的iterator()方法,从而具备了迭代的能力。但是,相比于另外两个接口,List还单独提供了listIterator()方法,增强了迭代能力。iterator()方法返回Iterator迭代器,listIterator()方法返回ListIterator迭代器,并且ListIterator是Iterator的子接口。ListIterator在Iterator的基础上,增加了向前遍历的支持,增加了在迭代过程中修改数据的支持。

延伸阅读

​ ArrayList的关键代码如下:

// 默认容量
private static final int DEFAULT_CAPACITY = 10;
// 空数组(指定容量)
private static final Object[] EMPTY_ELEMENTDATA = {};
// 空数组(默认容量)
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
// 元素数组
transient Object[] elementData;
// 元素个数
private int size;

// 创建默认容量的集合(在首次添加数据时分配容量)
public ArrayList() {
    this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}

// 创建指定容量的集合
public ArrayList(int initialCapacity) {
    if (initialCapacity > 0) {
        this.elementData = new Object[initialCapacity];
    } 
    ...
}

// 追加数据
public boolean add(E e) {
    // 先扩容
    ensureCapacityInternal(size + 1);
    // 再追加
    elementData[size++] = e;
    return true;
}

// 扩容的底层逻辑
private void grow(int minCapacity) {
    int oldCapacity = elementData.length;
    // 1.5倍
    int newCapacity = oldCapacity + (oldCapacity >> 1);
    // newCapacity有可能整数溢出
    if (newCapacity - minCapacity < 0)
        newCapacity = minCapacity;
    // newCapacity有可能超出上限
    if (newCapacity - MAX_ARRAY_SIZE > 0)
        newCapacity = hugeCapacity(minCapacity);
    // 拷贝数组
    elementData = Arrays.copyOf(elementData, newCapacity);
}
编辑于 2021-09-15 10:33:22 回复(0)
ArrayList底层基于数组实现,内部封装了Object类型的数组,实现了list接口,通过默认构造器创建容器时,该数组被初始化为一个空数组,首次添加数据时再将其初始化为容量为10的数组,也可以通过有参构造器显式指定数组长度;当添加的数据超出数组长度时触发自动扩容,将旧数据拷贝到新数组中,新数组为就数组的1.5倍,相对于同为继承list的LinkedList来说,查询快,增改删较慢,则LinkedList相反
发表于 2021-12-11 11:07:28 回复(0)
Arraylist底层基于数组实现,内部封装了Object类型的数组,实现了list接口,通过默认的构造器创建容器时,该数组被初始化为一个空数组,首次添加数据时再将其初始化为容量为10的数组,也可以通过有参构造器显式指定数组长度;当添加的数据超出数组长度时触发自动扩容机制,将旧数据拷贝到新数组中,新数组为旧数组的1.5倍,相对于同为继承list的LinkedList来说,查询快,增删改较慢,它的底层代码,会有一个老数组和新数组的比较,如果扩容之后的新数组小于老数组,则还会继续使用老数组,如果新数组大于老数组,那么使用新数组。

发表于 2022-09-17 22:24:34 回复(0)
object数组实现,初始化时是个空数组,当往里面加数据时会是默认长度10的数组,当长度超过10后会进行扩容,扩容后的长度大概是扩容前的1.5倍(源码里面是用原长度加上原长度右移2位的长度)
发表于 2024-05-17 16:49:49 回复(0)
ArrayList底层给予数组实现,内部封装了Object类型的数组,实现了list接口,通过默认的构造器创建容器时,该数组被初始化一个空数组,首次添加数据时再将其初始化成容量为10,也可以通过有参构造器显式的指定数组长度,当添加的数据超出数组长度时触发自动扩容机制 从而产生一个容量时原数组的1.5倍的新数组,并将旧数据拷贝到新数组中。相对于同为继承list的LinkedList来说,ArrayList的查询快,增删改较慢,而LinkedList反之。
发表于 2022-11-10 13:28:08 回复(0)
ArrayList是基于数组实现的,内部封装了Object类型的数组,同样是实现List接口,与LinkList相比ArrayList可以通过索引查询,在查询上有着很大的优势,但增删改由于数组连续存储的特性,效率较低。ArrayList的初始容量是10,在添加元素超出数组元素时会进行自动扩容,先根原来容量的1.5倍创建一个新的数组,然后将原来数组中的数据拷贝到新数据中,我们也可以通过有参构造器来构造容器,从而显示指定数组的容量
发表于 2022-06-21 18:00:13 回复(0)