介绍
特性:元素可重复,容许null,查询效率高,插入和删除效率低,线程不安全;
主要用到下面两个方法:
Arrays.copyOf(T[] original, int newLength);根据newLength创建了一个新的数组,然后调用System.arraycopy()将原数组original内容复制到新数组中,并且将新数组返回;
System.arraycopy(Object src,int srcPos, Object dest,int destPos,int length);将一个数组的指定个数元素复制到另一个数组中;arrayCopy(arr1, 2, arr2, 5, 10) 意思是;将arr1数组里从索引为2的元素开始, 复制到数组arr2里的索引为5的位置, 复制的元素个数为10个.
添加方法:
add(E e),add(int index, E element),addAll();
add(E e):返回是否添加成功;
public boolean add(E e) {
//检查容量,
ensureCapacityInternal(size + 1); // Increments modCount!!
//给数组对应下标赋值
elementData[size++] = e;
return true;
}
private void ensureCapacityInternal(int minCapacity) {
//是否为空数组
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
}
ensureExplicitCapacity(minCapacity);
}
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;
//newCapacity为oldCapacity的1.5倍;
int newCapacity = oldCapacity + (oldCapacity >> 1);
//判断增加后容量和最小需要容量大小;
if (newCapacity - minCapacity < 0)
newCapacity = minCapacity;
if (newCapacity - MAX_ARRAY_SIZE > 0)
newCapacity = hugeCapacity(minCapacity);
//创建一个长度为newCapacity的新数组,并且将数组elementData的元素复制到新数组中,并且返回该数组,赋值给elementData;
// minCapacity is usually close to size, so this is a win:
elementData = Arrays.copyOf(elementData, newCapacity);
}
add(int index, E element):在指定下标添加元素;
public void add(int index, E element) {
//检查下标是否越界
if (index > size || index < 0)
throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
//检查容量
ensureCapacityInternal(size + 1); // Increments modCount!!
//腾位置,将当前数组从index开始的数据,复制到index+1开始的位置,复制个数为size-index;
System.arraycopy(elementData, index, elementData, index + 1,
size - index);
//给数组对应下标赋值;
elementData[index] = element;
size++;
}
addAll(Collection<? extends E> c)和addAll(int index, Collection<? extends E> c)分别和add(E e),add(int index, E element)对应;
插入的步骤
1:检查容量,如果需要扩容,调用Arrays.copyOf(),创建一个新数组,容量为newLength,并且调用System.arraycopy()将原数组中的元素复制到新数组;
2:腾位置,插入n个元素,插入位置index(不考虑尾部直接插入的情况下),先将当前数组从index开始的数据,复制到index+n开始的位置,依次对应;
3:插入,n=1,给数组对应下标赋值;n>1,将n个元素组成的数组,调用System.arraycopy() 复制到从index开始的位置;
由此可以看出,数组的插入效率低,时间复杂度为O(n)
get()和set()
get():判断下标是否越界,不越界,直接取出对应值;查询效率高。时间复杂度O(1),常数级别;
public E get(int index) {
if (index >= size)
throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
return (E) elementData[index];
}
set(),效率也很高,时间复杂度O(1);
public E set(int index, E element) {
if (index >= size)
throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
E oldValue = (E) elementData[index];
elementData[index] = element;
return oldValue;
}
删除
remove(int index):删除指定下标的元素;
public E remove(int index) {
if (index >= size)
throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
modCount++;
E oldValue = (E) elementData[index];
//需要移动元素的个数
int numMoved = size - index - 1;
//大于0,将下标index+1开始的numMoved个元素,移动到下标index位置上;
if (numMoved > 0)
System.arraycopy(elementData, index+1, elementData, index,
numMoved);
elementData[--size] = null; // clear to let GC do its work
return oldValue;
}
remove(Object o):删除指定元素;先找到数组中最先出现相同元素的下标;再根据下标删除;
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;
}
//和remove(int index)相同
private void fastRemove(int index) {
modCount++;
int numMoved = size - index - 1;
if (numMoved > 0)
System.arraycopy(elementData, index+1, elementData, index,
numMoved);
elementData[--size] = null; // clear to let GC do its work
}
removeAll():从数组elementData中 删除c包含的数组elementData的元素;
public boolean removeAll(Collection<?> c) {
//非空判断
Objects.requireNonNull(c);
return batchRemove(c, false);
}
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++)
//c中不包含elementData的元素,重新放入到数组elementData中
if (c.contains(elementData[r]) == complement)
elementData[w++] = elementData[r];
} finally {
// Preserve behavioral compatibility with AbstractCollection,
// even if c.contains() throws.
//出现异常
if (r != size) {
System.arraycopy(elementData, r,
elementData, w,
size - r);
w += size - r;
}
//说明c中只包含数组elementData中部分元素;
if (w != size) {
//清除空间,赋值为null;
// 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;
}
迭代器(Iterator):在迭代过程中可以删除元素;
hasNext:判断游标cursor右侧是否还有元素;判断cursor是否小于size;
next():返回游标cursor对应的数据,并将游标cursor+1;
remove():删除游标cursor右侧的数据;在执行完next()方法之后,只能执行一次,否则会报错;
比较
ArrayList:元素可重复,容许null,查询效率高,插入和删除效率低,线程不安全;
Vector:线程安全,(增删改查)都是synchronized方法,效率低,其他和ArrayList一致;都是以数组作为底层;
CopyOnWriteArrayList:是concurrent包中的,和Vector类似,线程安全,(增删改)用的同步代码块,查操作异步的,不继承AbstractList;其他操作一样;没有缓冲区,在对其实例进行修改操作(add/remove等)会新建一个数据并修改,修改完毕之后,再将原来的引用指向新的数组,也就没有了ConcurrentModificationException错误。可以边循环,别做其他操作; 适用于读操作频繁;
Stack(栈):是Vector的子类,也是线程安全的;同时还具有LIFO(后进先出);push()入栈(添加一个元素);
主要方法:peek()获取栈顶的元素值;pop()出栈(从栈顶删除该元素),并且返回该值;search():判断栈中是否存在该元素,返回距离栈顶最近的距离;
如有问题请多指教,谢谢!