ArrayList Source Code
说明
承了RanddomAccess —->遍历的话用for最好
elementData是数组 所以在顺序插入和随机访问的情况下使用这个最好
list可以放入重复的值
构造方法
先将继承集合接口Collection的C(如hashset)转化为数组 如果数组长度不是0 而且对象不是Object[] (elementData类型)则将转成Object[]
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;
}
}
方法
trimToSize()
public void trimToSize() {
modCount++;
if (size < elementData.length) {
elementData = (size == 0)
? EMPTY_ELEMENTDATA
: Arrays.copyOf(elementData, size);
}
}
说明:
Trims the capacity of this ArrayList instance to be the list’s current size. An application can use this operation to minimize the storage of an ArrayList instance.
将ArrayList实例的容量 变为list的当前大小 . 应用可以使用这个操作最小化ArrayList实例的存储
获取ArrayList的元素个数是用size. 而length是ArrayList申请的容量大小. 便于不用每次增加的时候都去进行扩容操作.在isEmpty()方法里判断是否为null的时候 直接用size==0判断
modCount是什么? The number of times this list has been structurally modified
这个字段主要防止多线程操作的情况下 ArrayList发生结构性的变化. 例如一个线程正在遍历 而另一个线程正在remove. 在遍历的过程中 会发现某个元素为null 这时 modCount 会告诉迭代器 让其抛出ConcurrentModificationException.如果没有这一个变量,那么系统肯定会报异常ArrayIndexOutOfBoundsException,这样的异常显然不是应该出现的(这些运行时错误都是使用者的逻辑错误导致的,我们的JDK那么高端,不会出现使用错误,我们只抛出使用者造成的错误,而这个错误是设计者应该考虑的),为了避免出现这样的异常,定义了检查。—从这里也可以看出 ArrayList是非线程安全的
参考知乎:https://www.zhihu.com/question/24086463/answer/64717159
add()
说明:Appends the specified element to the end of this list 添加指定元素到list尾部
public boolean add(E e) {
ensureCapacityInternal(size + 1); // Increments modCount!!
elementData[size++] = e;
return true;
}
private void ensureCapacityInternal(int minCapacity) {
ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
}
private static int calculateCapacity(Object[] elementData, int minCapacity) {
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
return Math.max(DEFAULT_CAPACITY, minCapacity);
}
return minCapacity;
}
在 空参初始化的时候 elementData=DFAULTCAPACITY_EMPTY_ELEMENTDATA 然后返回最小容量是默认容量 10 还是size+1 .然后确定明确的容量ensureExplicitCapacity 如果大于10 则扩容 grow
private void ensureExplicitCapacity(int minCapacity) {
modCount++;
// overflow-conscious code
if (minCapacity - elementData.length > 0)
grow(minCapacity);
}
private void grow(int minCapacity) {
// overflow-conscious code
int oldCapacity = elementData.length;
int newCapacity = oldCapacity + (oldCapacity >> 1);
// 再判断一下新数组的容量够不够,够了就直接使用这个长度创建新数组,
// 不够就将数组长度设置为需要的长度
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);
}
如何扩容?
看到第二行 就知道 容量变成原来的1.5倍 然后copy到新的数组
更详细的参考:https://blog.csdn.net/wangb_java/article/details/79515302
remove(int index)
说明 Removes the element at the specified position in this list Shifts any subsequent elements to the left 移除list指定位置的元素 将之后的所有元素向左转移
public E remove(int index) {
rangeCheck(index);//判断是否越界
modCount++;
E oldValue = elementData(index);
int numMoved = size - index - 1;//获取index位置开始到最后一个位置的个数
if (numMoved > 0)
System.arraycopy(elementData, index+1, elementData, index,
numMoved); // 将elementData数组index+1位置开始拷贝到elementData从index开始的空间
elementData[--size] = null; // clear to let GC do its work
return oldValue;
}
batchRemove(Collection
private boolean batchRemove(Collection<?> c, boolean complement) {
final Object[] elementData = this.elementData;
int r = 0, w = 0;
boolean modified = false;
try {
for (; r < size; r++)
if (c.contains(elementData[r]) == complement)
elementData[w++] = elementData[r];// 直接将r位置的元素赋值给w位置的元素,w自增
} finally {
//保留与AbstractCollection的行为兼容性 防止抛出异常导致上面r的右移过程没完成
// Preserve behavioral compatibility with AbstractCollection,
// even if c.contains() throws.
if (r != size) {
System.arraycopy(elementData, r,
elementData, w,
size - r);
w += size - r;
}
if (w != size) {
// clear to let GC do its work
for (int i = w; i < size; i++)
elementData[i] = null;
modCount += size - w;
size = w;
modified = true;
}
}
return modified;
}
int indexOf(Object o)
说明:Returns the index of the first occurrence of the specified element in this list, or -1 if this list does not contain the element. More formally, returns the lowest index i such that (o==null ? get(i)==null : o.equals(get(i))), or -1 if there is no such index.
大体意识是 找到指定元素o在list第一次出现的位置. 如果 list中没有o则返回-1.
public int indexOf(Object o) {
if (o == null) {//元素o 为null 则得到该数组中第一个元素为null的下标
for (int i = 0; i < size; i++)
if (elementData[i]==null)
return i;
} else {
for (int i = 0; i < size; i++)
if (o.equals(elementData[i]))
return i;
}
return -1;
}
Object clone()
说明:Returns a shallow copy of this ArrayList instance. (The elements themselves are not copied.)
返回ArrayList实例的浅复制 元素本身不被复制
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);
}
}
这个 浅复制 和 深复制 的区别 参考:https://blog.csdn.net/accp_fangjian/article/details/2423252
toString()
说明:这个方法是继承父类AbstractCollection的Object的 toString()方法.
一般 对数组toString()输出的的值没有太大的意义.但是集合的toString()是打印出集合中的内容,就是因为 AbstractCollection
public String toString() {
Iterator<E> it = iterator();
if (! it.hasNext())
return "[]";
StringBuilder sb = new StringBuilder();//在不考虑 线程安全的情况下 字符串拼接最好用StringBuilder
sb.append('[');
for (;;) {
E e = it.next();
sb.append(e == this ? "(this Collection)" : e);
if (! it.hasNext())
return sb.append(']').toString();
sb.append(',').append(' ');
}
}