1、数组复制
借助工具类Arrays,实现数组复制
elementData = Arrays.copyOf(elementData, newCapacity);
底层调用System.arraycopy()
System.arraycopy(original, 0, copy, 0, Math.min(original.length, newLength));
数组复制在增加和删除元素时都会调用
2、增加元素,扩容机制
底层结构:
transient Object[] elementData;
private int size;
代码一:
如果是默认的空数组,则大小为0;
如果不是默认空数组,则大小为10;
如果容量超出,则扩容。
public void ensureCapacity(int minCapacity) {
int minExpand = (elementData != DEFAULTCAPACITY_EMPTY_ELEMENTDATA)
// any size if not default element table
? 0
// larger than default for default empty table. It's already
// supposed to be at default size.
: DEFAULT_CAPACITY;// 10
// 超出容量,进行扩容
if (minCapacity > minExpand) {
ensureExplicitCapacity(minCapacity);
}
}
private void ensureExplicitCapacity(int minCapacity) {
modCount++;
// overflow-conscious code
if (minCapacity - elementData.length > 0) // 超出数组长度
grow(minCapacity); // 扩容
}
代码二:
具体扩容机制:
新容量扩为旧容量的1.5倍;
若所需最小容量大于新容量,则新容量为所需最小容量;
若所需最小容量大于最大数组容量MAX_ARRAY_SIZE=Integer.MAX_VALUE-8,则新容量为最大容量Integer.MAX_VALUE;
private void grow(int minCapacity) {
// overflow-conscious code
int oldCapacity = elementData.length;
int newCapacity = oldCapacity + (oldCapacity >> 1);// 旧容量的1.5倍
if (newCapacity - minCapacity < 0)
newCapacity = minCapacity;
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);
}
private static int hugeCapacity(int minCapacity) {
if (minCapacity < 0) // overflow
throw new OutOfMemoryError();
return (minCapacity > MAX_ARRAY_SIZE) ?
Integer.MAX_VALUE :
MAX_ARRAY_SIZE;
}
问题一:如果数组初始容量过小,使用ArrayList的主要操作时增加元素,不断的增加,会出现什么后果?
数组需要不断的进行扩容,扩容的过程就是数组拷贝System.arraycopy的过程,每一次扩容就会开辟一块新的内存空间和数据的复制移动,这样势必对性能造成影响。
那么在这种以写为主(写会扩容,删不会缩容)场景下,提前预知性的设置一个大容量,便可减少扩容的次数,提高了性能。
问题二:数组复制需要开辟内存空间吗?
数组扩容伴随着开辟新建的内存空间以创建新数组然后进行数据复制,而数组复制不需要开辟新内存空间,只需将数据进行复制。
3、删除元素,不缩容
如果在已删除为主的场景下使用list,一直不停的删除而很少进行增加,那么会出现什么情况?再或者数组进行一次大扩容后,我们后续只使用了几个空间,会出现上面情况?当然是空间浪费啦啦啦,怎么办呢?
/**
* 将底层数组的容量调整为当前实际元素的大小,来释放空间。
*/
public void trimToSize() {
modCount++;
if (size < elementData.length) {
elementData = (size == 0)
? EMPTY_ELEMENTDATA
: Arrays.copyOf(elementData, size);
}
}