Java-ArrayList源码解析

前言

面试中经常会被问到ArrayList。

经常看面试题的都知道这么回答:
ArrayList是一个有序集合,底层是数组实现的,默认是10,每次增长50%,并且线程不安全,查询速度快,插入速度慢

源码解析

下面来剖析一下集合里面的ArrayList

ArrayList是在JRE里面的rt.jar的java.util包中
这里写图片描述

根据源码,我们可以发现它继承自抽象类AbstractList,实现了List, RandomAccess, Cloneable, Serializable这些接口,并且通过通配符E来表述了它支持泛型。

AbstractList抽象类提供了add增加、remove删除、indexOf、lastIndexOf、clear、addAll等方法,并重写了equals和hashCode方法

初始化、初始容量和最大容量

ArrayList包含了两个重要的对象:elementData 和 size。

(01) elementData 是”Object[]类型的数组”,它保存了添加到ArrayList中的元素。实际上,elementData是个动态数组,我们能通过构造函数 ArrayList(int initialCapacity)来执行它的初始容量为initialCapacity;如果通过不含参数的构造函数ArrayList()来创建ArrayList,则elementData的容量默认是10。elementData数组的大小会根据ArrayList容量的增长而动态的增长,具体的增长方式,请参考源码分析中的ensureCapacity()函数。

(02) size 则是动态数组的实际大小。

我们看源码
这里写图片描述

//默认的容量
private static final int DEFAULT_CAPACITY = 10;
//新new出来不指定大小的ArrayList elementData=DEFAULTCAPACITY_EMPTY_ELEMENTDATA
transient Object[] elementData; 
private int size;   //ArrayList的size

//构造方法,带参数:
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);
    }
}

继续往下读,发现有个trimToSize方法

    /**
     * Trims the capacity of this <tt>ArrayList</tt> instance to be the
     * list's current size.  An application can use this operation to minimize
     * the storage of an <tt>ArrayList</tt> instance.
     */
    public void trimToSize() {
        modCount++;
        if (size < elementData.length) {
            elementData = (size == 0)
              ? EMPTY_ELEMENTDATA
              : Arrays.copyOf(elementData, size);
        }
    }

trimToSize是可以用该方法来修整此ArrayList实例的是列表的当前大小的容量,就是List里面有多少个值,容量就是多少

ArrayList默认不带参数的容量是10,假如new的时候指定了容量,那么直接就是那个容量,那么最大的容量是多少,根据源码可知MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8,即2^31-1,就是2的31次方的值再减1

private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;

这里写图片描述

add与容量增长

那么ArrayList的add是如何增长的呢?
看下面
元素被add的时候方法:

public boolean add(E e) {
    ensureCapacityInternal(size + 1);  // Increments modCount!!
    elementData[size++] = e;
    return true;
}

调用ensureCapacityInternal,ensureCapacityInternal调用ensureExplicitCapacity,通过判断if (minCapacity - elementData.length > 0)来调用grow增长一次,grow方法是私有的,增长的关键在于int newCapacity = oldCapacity + (oldCapacity >> 1);
(oldCapacity >> 1)表示oldCapacity 向右移动一位,也就是除以2
所以是增长一半

增长完毕以后再elementData = Arrays.copyOf(elementData, newCapacity)复制元素到elementData中

>>是表示位运算符,就是往右移动1位,如果num >> n,表示num除以2的n次方
<<是表示向左移动,如果num << n,表示num乘以2的n次方

这里写图片描述

这里写图片描述

ArrayList的克隆

ArrayList的克隆是讲元素用Arrays.copyOf复制到新的对象

public Object clone() {
    try {
        ArrayList<?> v = (ArrayList<?>) super.clone();
        v.elementData = Arrays.copyOf(elementData, size);
        v.modCount = 0;
        return v;
    } catch (CloneNotSupportedException e) {
        // this shouldn't happen, since we are Cloneable
        throw new InternalError(e);
    }
}

remove删除

这里写图片描述

并且也有内部私有化的batchRemove方法,批量删除,主要用于retainAll中
retainAll:保留指定集合,剩下的全部删除

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值