数组拷贝
ArrayList 底层拷贝数组方法:
System.arraycopy(Object src, int srcPos, Object dest, int destPos, int length)
将指定源数组中的数组从指定位置复制到目标数组的指定位置
add 方法
JDK 1.8及以后版本,在 new ArrayList<>() 的时候,是没有分配空间的。使用的是空数组
public ArrayList() {
// DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {}
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
当我们第一次使用 add 方法时候,才会初始化数组,数组大小为10
public boolean add(E e) {
ensureCapacityInternal(size + 1); // Increments modCount!!
elementData[size++] = e;
return true;
}
ensureCapacityInternal 方法是用来确保新增元素时能够放的进我们的数组的。
ensureCapacityInternal 是如何 ArrayList内部数组的容量足够用的呢?
/**
calculateCapacity: 返回添加一个元素后的数组长度
*/
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); // 返回 10
}
return minCapacity;
}
ensureExplicitCapacity 方法确保容量够用
private void ensureExplicitCapacity(int minCapacity) {
modCount++;
// 判断容量是否够用
if (minCapacity - elementData.length > 0)
grow(minCapacity); // 数组扩容方法
}
grow 方法:将数组容量扩大到原来的1.5倍,并且将原数组中的数据拷贝到新数组中
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);
}
add 方法总结:
第一次调用 add 方法时,ArrayList 中的数组初始化,初始化大小为10,然后将 元素添加到数组中。
以后再调用 add 方法时,先判断是否需要扩容?
如不需要扩容,则直接添加元素到末尾
如需要扩容,则先将容量扩大到原来的 1.5 倍,再将原数组中的数据拷贝到新数组中,最后将原始添加到数组中的末尾
注意了:
ArrayList 底层维护的动态数组是
transient Object[] elementData;
ArrayList 实际存储数据的大小是 size, 而不是 elementData 数组的长度
private int size;
上面我们所说的将元素添加到末尾是指,将原始添加到 elementData[size] = e
get 方法
用于获取指定位置上的元素
public E get(int index) {
rangeCheck(index); // 检查获取元素的下标,如果大于 size,则抛出异常
return elementData(index);
}
/**
返回 elementData 数组中下标为 index的元素
*/
E elementData(int index) {
return (E) elementData[index];
}
Set方法
用于替换指定位置的元素,并返回原位置上的元素返回
public E set(int index, E element) {
rangeCheck(index);
E oldValue = elementData(index);
elementData[index] = element;
return oldValue;
}
remove(int index) 方法
用于删除指定下标的元素,并将删除元素返回
public E remove(int index) {
rangeCheck(index);
modCount++;
E oldValue = elementData(index); // 获取删除元素
int numMoved = size - index - 1; // 计算往前移动元素的个数
if (numMoved > 0)
System.arraycopy(elementData, index+1, elementData, index,
numMoved); // index下标后面的元素往前移动一位
elementData[--size] = null; // 清除数组中最后一个元素
return oldValue;
}
remove(Object o) 方法
作用是将指定对象从 list集合中删除,删除成功返回 true,删除失败返回false。
/**
数组遍历,找到要删除元素的下标,
通过下标进行删除(调用 System.arraycopy 方法进行数组前移)
*/
public boolean remove(Object o) {
if (o == null) {
for (int index = 0; index < size; index++)
if (elementData[index] == null) {
fastRemove(index);
return true;
}
} else {
for (int index = 0; index < size; index++)
if (o.equals(elementData[index])) {
fastRemove(index);
return true;
}
}
return false;
}
contains(Object o) 方法
用于判断元素是否在 List 集合中,如果在的话返回找到的第一个元素在集合中的位置下标,不在的话就返回 -1
public boolean contains(Object o) {
return indexOf(o) >= 0;
}
/**
indexOf 方法:底层也是用 for 循环遍历挨个对比,返回找到的第一个元素下标
*/
public int indexOf(Object o) {
if (o == 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;
}
toArray() 方法
作用是将集合转换为数组,通过源码发现它底层使用的也是 System.arraycopy 方法
public Object[] toArray() {
return Arrays.copyOf(elementData, size);
}
addAll(Collection<? extends E> c) 方法
作用是往集合里边添加另一个集合,返回添加是否成功
public boolean addAll(Collection<? extends E> c) {
Object[] a = c.toArray(); // 1.将集合转换数组
int numNew = a.length;
ensureCapacityInternal(size + numNew); // 确保数组中能装的下集合中的元素
System.arraycopy(a, 0, elementData, size, numNew); // 将集合中元素拷贝到数组中
size += numNew; // ArrayList的实际存储大小
return numNew != 0;
}
forEach(Consumer<? super E> action) 方法
用来遍历 List 集合中的元素,传入参数是 Consumer接口的实现类。
public void forEach(Consumer<? super E> action) {
Objects.requireNonNull(action);
final int expectedModCount = modCount;
@SuppressWarnings("unchecked")
final E[] elementData = (E[]) this.elementData;
final int size = this.size;
for (int i=0; modCount == expectedModCount && i < size; i++) { // 遍历 集合中元素
action.accept(elementData[i]); // 调用accept 方法对每一个元素进行处理
}
if (modCount != expectedModCount) {
throw new ConcurrentModificationException();
}
}
举例:打印集合中的元素
ArrayList<String> list = new ArrayList<>();
list.add("a1");
list.add("a2");
list.add("a3");
list.add("a4");
list.forEach(new Consumer<String>() {
@Override
public void accept(String s) {
System.out.println(s);
}
});
sort(Comparator<? super E> c) 方法
用于对集合中元素进行排序,参数是Comparator 比较器接口。
public void sort(Comparator<? super E> c) {
final int expectedModCount = modCount;
Arrays.sort((E[]) elementData, 0, size, c);
if (modCount != expectedModCount) {
throw new ConcurrentModificationException();
}
modCount++;
}
举例:
ArrayList<String> list = new ArrayList<>();
list.add("a31");
list.add("a33");
list.add("a1");
list.add("a17");
list.sort(new Comparator<String>() {
@Override
public int compare(String o1, String o2) {
return o1.compareTo(o2);
}
});
list.forEach((s) -> {
System.out.println(s);
});