数组(定长,有序的,随机访问)。ArrayList是Java在数组的基础上进行衍生出来的Java里的一种数据结构,它在拥有数据的特性之外,增加了可变性 (动态数组)。
| 属性 | 备注 |
|---|---|
| DEFAULT_CAPACITY | 默认初始大小 |
| EMPTY_ELEMENTDATA | 空数组,申明了长度可能为0 |
| DEFAULTCAPACITY_EMPTY_ELEMENTDATA | 空数组 (无参构造时候的默认值) |
| elementData | 承认数组元素 |
| size | 数组元素数量,注意和Lenth的 |
/**带有参数的构造方法,如果长度为0 则给一个默认的常量。*/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); }}/** 直接给一个默认的空数组*/public ArrayList() { this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;} public ArrayList(Collection<? extends E> c) { Object[] a = c.toArray(); if ((size = a.length) != 0) { if (c.getClass() == ArrayList.class) { elementData = a; } else { elementData = Arrays.copyOf(a, size, Object[].class); } } else { // replace with empty array. elementData = EMPTY_ELEMENTDATA; } }以上三种构建,两种有参,一种无参。主要区别就是 DEFAULTCAPACITY_EMPTY_ELEMENTDATA和 EMPTY_ELEMENTDATA在不同场景分别给值。EMPTY_ELEMENTDATA是带参数的构建函数里长度为0的默认共享数组DEFAULTCAPACITY_EMPTY_ELEMENTDATA是不带参数构造函数里长度为0的共享数组
对比老版本的JDK来看,会对初始化数组的时候解决是数度长度为空的情况下会 new Object[initialCapatity]的情况,减少不必要的内存开支。
在扩容机制也会针对不同的构造出的数组进行不同的扩容机制。
public boolean add(E e) { //确保容量够不够,扩容机制 ensureCapacityInternal(size + 1); // Increments modCount!! elementData[size++] = e; return true; } // step 1 private void ensureCapacityInternal(int minCapacity) { ensureExplicitCapacity(calculateCapacity(elementData, minCapacity)); } // step 2. 计算容量 private static int calculateCapacity(Object[] elementData, int minCapacity) { //判断是否是无参构造来的,为10个容量大小 if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) { return Math.max(DEFAULT_CAPACITY, minCapacity); } //否则就给即将增长的长度 return minCapacity; } // step 3 private void ensureExplicitCapacity(int minCapacity) { //修改次数 modCount++; // 即将增长的长度比现的数组长度大就扩容 if (minCapacity - elementData.length > 0) grow(minCapacity); } // step 4 private void grow(int minCapacity) { //原始长度 int oldCapacity = elementData.length; //新长度 = 原始长度 + (原始长度/2) int newCapacity = oldCapacity + (oldCapacity >> 1); if (newCapacity - minCapacity < 0) newCapacity = minCapacity; //尽量不扩容到 Intege 的最大值, 因为有些Vm的设计超过 MAX_ARRAY_SIZE 可能会 OOM错误 (OutOfMemoryError: Requested array size exceeds VM limit) if (newCapacity - MAX_ARRAY_SIZE > 0) newCapacity = hugeCapacity(minCapacity); // minCapacity is usually close to size, so this is a win: elementData = Arrays.copyOf(elementData, newCapacity); }add函数,可以看出来,每次扩容都是本身的 0.5 倍Intege最大值,但也是在实际元素数量真的超过 MAX_ARRAY_SIZE的情况下。MAX_ARRAY_SIZE的原因是 OutOfMemoryError: Requested array size exceeds VM limit借助了系统函数
/** * 第一个参数是要被复制的数组 * * 第二个参数是被复制的数字开始复制的下标 * * 第三个参数是目标数组,也就是要把数据放进来的数组 * * 第四个参数是从目标数组第几个下标开始放入数据 * * 第五个参数表示从被复制的数组中拿几个数值放到目标数组中 */public static native void arraycopy(Object src, int srcPos, Object dest, int destPos, int length);把最后一个元素置为null, size = size -1
elementData[--size] = null; // clear to let GC do its workfor``foreach里删除元素。ArrayList在多线程环境中是不安全的本文来自博客园,作者:乌托拉赛文,转载请注明原文链接:https://www.cnblogs.com/m78-seven/p/16301040.html