ArrayList扩容

 

面试的时候面试官让自己设计一个ArrayList,做的一塌糊涂,在秋招路上继续补强

一.ArrayList的属性

   private static final long serialVersionUID = 8683452581122892189L;

    /**
     * 默认长度
     */
    private static final int DEFAULT_CAPACITY = 10;

    /**
     * 初始化一个空数组
     */
    private static final Object[] EMPTY_ELEMENTDATA = {};

    /**
     * 无参数构造器的时候会用到
     */
    private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};

    /**
     * 当前数组存放对象的地方
     */
    transient Object[] elementData; // non-private to simplify nested class access

    /**
     *数组中元素个数
     * @serial
     */
    private int size;

二.构造器

1. 带参数的构造器,长度是initialCapacity,初始化长度不为0,就创建一个新的数组

//Constructs an empty list with the specified initial capacity.
   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.空构造器,默认数组

 public ArrayList() {
        this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
    }

3.创建一个以集合类为参数的数组

将集合类转换成数组,如果数组size是 0 把EMPTY_ELEMENTDATA的地址赋给elementData,如果size不是0,则执行Arrays.copy方法,把collection对象的内容(可以理解为深拷贝)copy到elementData中。

    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;
        }
    }

 

### Java ArrayList 扩容机制与源码分析 #### 1. ArrayList 的初始化 当使用无参构造函数创建 `ArrayList` 时,内部会初始化一个空数组 `DEFAULTCAPACITY_EMPTY_ELEMENTDATA`,其长度为 0。此时,`ArrayList` 并不会分配实际的存储空间[^3]。 ```java public ArrayList() { this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA; } ``` 只有在调用 `add()` 方法添加第一个元素时,才会触发扩容操作,确保有足够的容量来存储新元素[^4]。 #### 2. 扩容触发条件 `ArrayList` 的扩容机制主要通过 `ensureCapacityInternal()` 方法实现。每当尝试添加新元素时,该方法会检查当前数组的容量是否足够。如果容量不足,则会调用 `grow()` 方法进行扩容[^5]。 ```java private void ensureCapacityInternal(int minCapacity) { if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) { minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity); } ensureExplicitCapacity(minCapacity); } private void ensureExplicitCapacity(int minCapacity) { modCount++; if (minCapacity - elementData.length > 0) grow(minCapacity); } ``` #### 3. 扩容实现细节 扩容的核心逻辑由 `grow()` 方法完成。默认情况下,`ArrayList` 的容量会增加到原容量的 1.5 倍(即 `(oldCapacity * 3)/2 + 1`),以减少频繁扩容带来的性能开销。 ```java private void grow(int minCapacity) { int oldCapacity = elementData.length; int newCapacity = oldCapacity + (oldCapacity >> 1); // 增加原容量的一半 if (newCapacity - minCapacity < 0) newCapacity = minCapacity; if (newCapacity - MAX_ARRAY_SIZE > 0) newCapacity = hugeCapacity(minCapacity); elementData = Arrays.copyOf(elementData, newCapacity); } ``` 这里使用了 `Arrays.copyOf()` 方法来创建一个新的数组,并将原有数据复制到新数组中[^5]。 #### 4. 扩容中的特殊情况处理 - 如果计算出的新容量仍小于所需的最小容量 `minCapacity`,则直接将容量设置为 `minCapacity`。 - 如果新容量超过了 `MAX_ARRAY_SIZE`(即 `Integer.MAX_VALUE - 8`),则调用 `hugeCapacity()` 方法处理极端情况。 ```java private static int hugeCapacity(int minCapacity) { if (minCapacity < 0) // 溢出 throw new OutOfMemoryError(); return (minCapacity > MAX_ARRAY_SIZE) ? Integer.MAX_VALUE : MAX_ARRAY_SIZE; } ``` #### 5. 性能考量 每次扩容都会涉及数组的复制操作,时间复杂度为 O(n)。因此,频繁的扩容会导致性能下降。为了优化性能,可以在创建 `ArrayList` 时指定初始容量,避免多次扩容[^3]。 ```java 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); } } ``` --- ### 示例代码 以下是一个简单的代码示例,展示 `ArrayList` 的扩容过程: ```java import java.util.ArrayList; public class ArrayListDemo { public static void main(String[] args) { ArrayList<Integer> list = new ArrayList<>(); for (int i = 0; i < 15; i++) { list.add(i); System.out.println("Size: " + list.size() + ", Capacity: " + getCapacity(list)); } } private static int getCapacity(ArrayList<?> list) { return java.lang.reflect.Array.getLength(((ArrayList<?>) list).toArray()); } } ``` 输出结果将显示每次扩容后的新容量变化。 --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值