一、构造方法
有三个重载的构造方法
1.直接newArrayList<>()的时候调用的时候就是调的这个构造方法,里面初始化了一个空数组,elementData是个Object数组
public ArrayList() {
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
2.传入初始化容量的时候,initialCapacity大于0就用传入的值初始化数组容量,initialCapacity=0的时候跟无参构造方法的效果一样是初始化一个空数组,initialCapacity<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);
}
}
3.传入一个Collection,先把传入的集合转为一个Object数组,
(1)如果数组大小大于0,则判断集合的类型是否为ArrayList,如果是arrayList则直接初始化elementData为传入的集合,否则把传入集合的内容拷贝到elementData
(2)如果数组大小等于0,则初始化一个空数组
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;
}
}
二、添加元素
1.调用add方法,在已有元素末尾插入,modCount记录元素修改次数+1,
public boolean add(E e) {
modCount++;
add(e, elementData, size);
return true;
}
然后调用内部的重载的私有add方法add(E e, Object[] elementData, int s),传入参数为(插入的元素,存储数据的数组,插入的位置),如果插入的位置等于数组长度,则进行扩容,否则将指定位置元素赋值为传入的值e,然后把数组元素数量+1
private void add(E e, Object[] elementData, int s) {
if (s == elementData.length)
elementData = grow();
elementData[s] = e;
size = s + 1;
}
扩容方法grow,调用重载的方法grow(int minCapacity),先拿到旧的容量oldCapacity,如果旧的容量大于0或者数组元素不为空,则将数组容量扩容为原来的1.5倍(没超过SOFT_MAX_ARRAY_LENGTH的情况下),然后拷贝元素到新数组中,再把新的数组赋值给elementData;如果数组原来的元素为空,则初始化数组长度为DEFAULT_CAPACITY=10
private Object[] grow(int minCapacity) {
int oldCapacity = elementData.length;
if (oldCapacity > 0 || elementData != DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
int newCapacity = ArraysSupport.newLength(oldCapacity,
minCapacity - oldCapacity, /* minimum growth */
oldCapacity >> 1 /* preferred growth */);
return elementData = Arrays.copyOf(elementData, newCapacity);
} else {
return elementData = new Object[Math.max(DEFAULT_CAPACITY, minCapacity)];
}
}
private Object[] grow() {
return grow(size + 1);
}
为什么是扩容为1.5倍?答案就在newLength方法里面,假设旧的容量是10,newLength的三个参数的值分别为10,1,5,newLenth方法实现,prefLength = 10 + Math.max(1, 5) = 15,这是没超过SOFT_MAX_ARRAY_LENGTH的情况下,超过SOFT_MAX_ARRAY_LENGTH就要走hugeLength方法
public static int newLength(int oldLength, int minGrowth, int prefGrowth) {
// preconditions not checked because of inlining
// assert oldLength >= 0
// assert minGrowth > 0
int prefLength = oldLength + Math.max(minGrowth, prefGrowth); // might overflow
if (0 < prefLength && prefLength <= SOFT_MAX_ARRAY_LENGTH) {
return prefLength;
} else {
// put code cold in a separate method
return hugeLength(oldLength, minGrowth);
}
}
hugeLength方法:
(1)如果扩容后溢出,就是超出Integer.MAX_VALUE,则抛出异常
(2)如果小于SOFT_MAX_ARRAY_LENGTH,则返回SOFT_MAX_ARRAY_LENGTH
(3)第三种情况,返回扩容后的长度
private static int hugeLength(int oldLength, int minGrowth) {
int minLength = oldLength + minGrowth;
if (minLength < 0) { // overflow
throw new OutOfMemoryError(
"Required array length " + oldLength + " + " + minGrowth + " is too large");
} else if (minLength <= SOFT_MAX_ARRAY_LENGTH) {
return SOFT_MAX_ARRAY_LENGTH;
} else {
return minLength;
}
}
关于SOFT_MAX_ARRAY_LENGTH的说明:值等于Integer.MAX_VALUE - 8,为什么是这个值?为了尽可能避免OOM,实际使用情况还要看对象的大小,可能到不了这个值就OOM了
public static final int SOFT_MAX_ARRAY_LENGTH = Integer.MAX_VALUE - 8;
三、删除元素
1.删除指定元素,先遍历数组,找到元素的位置i
public boolean remove(Object o) {
final Object[] es = elementData;
final int size = this.size;
int i = 0;
found: {
if (o == null) {
for (; i < size; i++)
if (es[i] == null)
break found;
} else {
for (; i < size; i++)
if (o.equals(es[i]))
break found;
}
return false;
}
fastRemove(es, i);
return true;
}
然后调用fastRemove删除:fastRemove先记录修改次数+1,然后从i+1开始元素整体往前移动一位,最大位置上的元素置为null
private void fastRemove(Object[] es, int i) {
modCount++;
final int newSize;
if ((newSize = size - 1) > i)
System.arraycopy(es, i + 1, es, i, newSize - i);
es[size = newSize] = null;
}
四、修改指定位置的元素
1.调用set方法,直接将对应位置的元素改为指定值,然后返回旧的元素
public E set(int index, E element) {
Objects.checkIndex(index, size);
E oldValue = elementData(index);
elementData[index] = element;
return oldValue;
}
五、查找指定位置元素
1.调用get方法,返回数组对应位置元素
public E get(int index) {
Objects.checkIndex(index, size);
return elementData(index);
}