ArrayList
ArrayList就是动态数组,用MSDN中的说法,就是Array的复杂版本,它提供了动态的增加和减少元素,实现了Collection和List接口,灵活的设置数组的大小等好处。 ——《百度》
优点:
1.可以自动改变大小
2.可以灵活地插入删除元素,设置数组大小
局限性:
1.线程不安全
2.比一般数组速度慢
ArrayList的继承关系:
默认初始化容量大小:10
private static final int DEFAULT_CAPACITY = 10;
构造方法
/**
*用指定的初始容量构造一个空列表。
*/
public ArrayList(int initialCapacity) {
super();
//如果用户初始化大小小于0抛异常
if (initialCapacity < 0)
throw new IllegalArgumentException("Illegal Capacity: "+initialCapacity);
//建立一个Object数组
this.elementData = new Object[initialCapacity];
}
/**
* 构造一个空列表,初始容量为10。
*/
public ArrayList() {
super();
this.elementData = EMPTY_ELEMENTDATA;
}
/**
* 按照集合的迭代器返回的顺序,构造一个包含指定集合元素的列表
*/
public ArrayList(Collection<? extends E> c) {
elementData = c.toArray();
size = elementData.length;
//当c.toArray返回的不是Object类型数组时将数组拷贝
if (elementData.getClass() != Object[].class)
elementData = Arrays.copyOf(elementData, size, Object[].class);
}
扩容
private void grow(int minCapacity) {
int oldCapacity = elementData.length;
//将容量扩展为原容量的1.5倍
int newCapacity = oldCapacity + (oldCapacity >> 1);
//扩容后的容量小于所需要的最小容量时,扩容容量赋值为最小容量的值
if (newCapacity - minCapacity < 0)
newCapacity = minCapacity;
//扩容后容量大于MAX_ARRAY_SIZE时,当所需最小容量大于MAX_ARRAY_SIZE,扩容容量赋值为Integer.MAX_VALUE否则赋值为MAX_ARRAY_SIZE
if (newCapacity - MAX_ARRAY_SIZE > 0)
newCapacity = hugeCapacity(minCapacity);
elementData = Arrays.copyOf(elementData, newCapacity);
}
private static int hugeCapacity(int minCapacity) {
if (minCapacity < 0)
return (minCapacity > MAX_ARRAY_SIZE) ?
Integer.MAX_VALUE :
MAX_ARRAY_SIZE;
}
查找字符串位置(对null需要单独查找)
/*
*查找字符串第一次出现的位置
*/
public int indexOf(Object o) {
//对null单独查找,找到null时返回下标
if (o == null) {
for (int i = 0; i < size; i++)
if (elementData[i]==null)
return i;
} else {
//不为null时,找到相同的返回下标
for (int i = 0; i < size; i++)
if (o.equals(elementData[i]))
return i;
}
//找不到时返回-1
return -1;
}
/*
*查找字符串最后一次出现的位置
*/
public int lastIndexOf(Object o) {
if (o == null) {
for (int i = size-1; i >= 0; i--)
if (elementData[i]==null)
return i;
} else {
for (int i = size-1; i >= 0; i--)
if (o.equals(elementData[i]))
return i;
}
return -1;
}
clone()
public Object clone() {
try {
@SuppressWarnings("unchecked")
ArrayList<E> v = (ArrayList<E>) super.clone();
v.elementData = Arrays.copyOf(elementData, size);
v.modCount = 0;
return v;
} catch (CloneNotSupportedException e) {
throw new InternalError();
}
}
获取列表中指定位置的元素
public E get(int index) {
rangeCheck(index);
//返回下标对应的元素
return elementData(index);
}
用指定的元素替换这个列表中指定位置的元素,并返回被替代的元素
public E set(int index, E element) {
rangeCheck(index);
//将指定位置元素放入oldValue中,将指定元素放入指定位置,返回指定位置原本的元素
E oldValue = elementData(index);
elementData[index] = element;
return oldValue;
}
插入元素(插入时,先插入,再size++)
/*
*将元素插入在末尾
*/
public boolean add(E e) {
ensureCapacityInternal(size + 1);
//将指定元素放入size标记的位置,size++
elementData[size++] = e;
return true;
}
/*
*将元素插入在指定位置
*/
public void add(int index, E element) {
rangeCheckForAdd(index);
ensureCapacityInternal(size + 1);
//将elementData数组中,从index号位置开始的size-index位copy到elementData中从index+1号位置开始
System.arraycopy(elementData, index, elementData, index + 1,
size - index);
//将指定元素放入数组的index位,然后size++
elementData[index] = element;
size++;
}
插入集合中的全部元素
/*
*将集合中全部的元素插入到末尾
*/
public boolean addAll(Collection<? extends E> c) {
Object[] a = c.toArray();
//要插入的位数
int numNew = a.length;
ensureCapacityInternal(size + numNew);
//将数组a从0号下标开始的numNew位copy到elementData数组中从size下标开始,size=size+numNew
System.arraycopy(a, 0, elementData, size, numNew);
size += numNew;
return numNew != 0;
}
/*
*将集合中全部的元素插入到指定位置
*/
public boolean addAll(int index, Collection<? extends E> c) {
rangeCheckForAdd(index);
Object[] a = c.toArray();
int numNew = a.length;
ensureCapacityInternal(size + numNew);
//要移动的位数
int numMoved = size - index;
if (numMoved > 0)
//进行移动
System.arraycopy(elementData, index, elementData, index + numNew,
numMoved);
//将要插入的元素放入,然后size=size+numNew
System.arraycopy(a, 0, elementData, index, numNew);
size += numNew;
return numNew != 0;
}
删除(删除时,先size–,再制空size)
/*
*删除指定位置的元素,并返回该元素
*/
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);
//先size--,再将size制空
elementData[--size] = null;
return oldValue;
}
/*
*删除第一次出现的指定元素
*/
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;
}
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;
}
/*
*删除指定范围的元素
*/
protected void removeRange(int fromIndex, int toIndex) {
modCount++;
//要移动的位数
int numMoved = size - toIndex;
将从toIndex开始的numNew位移动到fromIndex开始
System.arraycopy(elementData, toIndex, elementData, fromIndex,
numMoved);
//先将新size值改变,再将删除位制空,再将值赋给size
int newSize = size - (toIndex-fromIndex);
for (int i = newSize; i < size; i++) {
elementData[i] = null;
}
size = newSize;
}
/*
*从这个列表中删除所有包含在指定集合中的元素
*/
public boolean removeAll(Collection<?> c) {
return batchRemove(c, false);
}
/*
*只保留包含在指定集合中的元素
*/
public boolean retainAll(Collection<?> c) {
return batchRemove(c, true);
}
/*
*根据(c.contains(elementData[r]) == complement)保存所需要的元素
*/
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];
} finally {
if (r != size) {
System.arraycopy(elementData, r,
elementData, w,
size - r);
w += size - r;
}
if (w != size) {
for (int i = w; i < size; i++)
elementData[i] = null;
modCount += size - w;
size = w;
modified = true;
}
}
return modified;
}
LinkedList
LinkedList 是一个双向链表。它也可以被当作堆栈、队列或双端队列进行操作。
LinkedList 是一个继承于AbstractSequentialList的双向链表。 实现了 List 接口,能对它进行队列操作。实现了Deque 接口,即能将LinkedList当作双端队列使用。实现了Cloneable接口,即覆盖了函数clone(),能克隆。实现java.io.Serializable接口,这意味着LinkedList支持序列化,能通过序列化去传输。LinkedList 不是线程安全的。
LinkedList的继承关系:
构造函数
//默认构造函数,构造一个空列表
public LinkedList() {
}
//构造一个包含指定集合的列表
public LinkedList(Collection<? extends E> c) {
this();
addAll(c);
}
元素的获取
// 获取LinkedList的第一个元素
public E getFirst() {
final Node<E> f = first;
if (f == null)
throw new NoSuchElementException();
return f.item;
}
// 获取LinkedList的最后一个元素
public E getLast() {
final Node<E> l = last;
if (l == null)
throw new NoSuchElementException();
return l.item;
}
删除元素
// 删除LinkedList的第一个元素
public E removeFirst() {
final Node<E> f = first;
if (f == null)
throw new NoSuchElementException();
return unlinkFirst(f);
}
// 删除LinkedList的最后一个元素
public E removeLast() {
final Node<E> l = last;
if (l == null)
throw new NoSuchElementException();
return unlinkLast(l);
}
//删除指定元素
public boolean remove(Object o) {
//对null单独查找
if (o == null) {
for (Node<E> x = first; x != null; x = x.next) {
if (x.item == null) {
unlink(x);
return true;
}
}
} else {
//不为空时,在链表中查找与指定元素相同的元素,删除
for (Node<E> x = first; x != null; x = x.next) {
if (o.equals(x.item)) {
unlink(x);
return true;
}
}
}
return false;
}
//删除指定位置的元素
public E remove(int index) {
checkElementIndex(index);
return unlink(node(index));
}
添加元素
// 将元素添加到LinkedList的起始位置
public void addFirst(E e) {
linkFirst(e);
}
// 将元素添加到LinkedList的结束位置
public void addLast(E e) {
linkLast(e);
}
//将元素添加到LinkedList的结束位置,返回值为布尔类型
public boolean add(E e) {
linkLast(e);
return true;
}
//将集合全部添加到LinkedList中
public boolean addAll(Collection<? extends E> c) {
return addAll(size, c);
}
//用头插法插入全部元素
public boolean addAll(int index, Collection<? extends E> c) {
checkPositionIndex(index);
Object[] a = c.toArray();
int numNew = a.length;
if (numNew == 0)
return false;
Node<E> pred, succ;
if (index == size) {
succ = null;
pred = last;
} else {
succ = node(index);
pred = succ.prev;
}
for (Object o : a) {
@SuppressWarnings("unchecked") E e = (E) o;
Node<E> newNode = new Node<>(pred, e, null);
if (pred == null)
first = newNode;
else
pred.next = newNode;
pred = newNode;
}
if (succ == null) {
last = pred;
} else {
pred.next = succ;
succ.prev = pred;
}
size += numNew;
modCount++;
return true;
}
//在指定位置添加指定元素
public void add(int index, E element) {
checkPositionIndex(index);
if (index == size)
linkLast(element);
else
linkBefore(element, node(index));
}
//向链表尾增添元素
public boolean offer(E e) {
return add(e);
}
//向链表表头增添元素,成功返回true
public boolean offerFirst(E e) {
addFirst(e);
return true;
}
//向链表表尾增添元素,成功返回true
public boolean offerLast(E e) {
addLast(e);
return true;
}
判断LinkedList是否包含元素(o)
public boolean contains(Object o) {
return indexOf(o) != -1;
}
返回LinkedList的大小
public int size() {
return size;
}
清空链表
public void clear() {
for (Node<E> x = first; x != null; ) {
Node<E> next = x.next;
x.item = null;
x.next = null;
x.prev = null;
x = next;
}
first = last = null;
size = 0;
modCount++;
}
返回LinkedList指定位置的元素
public E get(int index) {
checkElementIndex(index);
return node(index).item;
}
设置index位置对应的节点的值为element,并返回index位置原本的值
public E set(int index, E element) {
checkElementIndex(index);
Node<E> x = node(index);
E oldVal = x.item;
x.item = element;
return oldVal;
}
获取指定位置的节点
Node<E> node(int index) {
// assert isElementIndex(index);
if (index < (size >> 1)) {
Node<E> x = first;
for (int i = 0; i < index; i++)
x = x.next;
return x;
} else {
Node<E> x = last;
for (int i = size - 1; i > index; i--)
x = x.prev;
return x;
}
}
查找节点所在位置
//从前向后查找
public int indexOf(Object o) {
int index = 0;
if (o == null) {
for (Node<E> x = first; x != null; x = x.next) {
if (x.item == null)
return index;
index++;
}
} else {
for (Node<E> x = first; x != null; x = x.next) {
if (o.equals(x.item))
return index;
index++;
}
}
return -1;
}
//从后往前查找
public int lastIndexOf(Object o) {
int index = size;
if (o == null) {
for (Node<E> x = last; x != null; x = x.prev) {
index--;
if (x.item == null)
return index;
}
} else {
for (Node<E> x = last; x != null; x = x.prev) {
index--;
if (o.equals(x.item))
return index;
}
}
return -1;
}
返回第一个节点,但不删除
//链表为空则返回null
public E peek() {
final Node<E> f = first;
return (f == null) ? null : f.item;
}
//链表为空则抛出异常
public E element() {
return getFirst();
}
返回第一个节点,并删除
//链表为空则返回null
public E poll() {
final Node<E> f = first;
return (f == null) ? null : unlinkFirst(f);
}
//链表为空则抛出异常
public E remove() {
return removeFirst();
}
ArrayList与LinkedList分别适合什么应用用场景
ArrayList:查询,ArrayList查询快是因为底层是由数组实现,通过下标定位数据快。写数据慢是因为复制数组耗时。
LinkedList:写数据,LinkedList底层是双向链表,查询数据依次遍历慢。写数据只需修改指针引用。