List 接口
1 ArrayList
ArrayList 实现了 List 接口,是顺序容器,即元素存放的数据与放进去的顺序相同,允许放入 null 元素,底层通过数组实现。
ArrayList 没有实现同步(synchronized),如果需要线程并发访问,可以手动同步,也可使用 Vector 替代。
1 底层数据结构
一个 Object 数组 和 元素数量。
transient Object[] elementData;
private int size;
复制代码
2 构造方法
Object[] elementData;
-
ArrayList(int initialCapacity) 构造一个大小为 initialCapacity 的数组{}
-
ArrayList() 构造一个 空数组{}
-
ArrayList(Collection<? extends E> c) 根据 容器c 构造数组
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);
}
}
public ArrayList() {
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
public ArrayList(Collection<? extends E> c) {
elementData = c.toArray();
if ((size = elementData.length) != 0) {
// c.toArray might (incorrectly) not return Object[]
if (elementData.getClass() != Object[].class)
elementData = Arrays.copyOf(elementData, size, Object[].class);
} else {
// replace with empty array.
this.elementData = EMPTY_ELEMENTDATA;
}
}
复制代码
3 自动扩容
在执行 add 方法时,会调用 ensureCapacityInternal 方法,确认 size+1 时容量是否够用,不够时进行扩容。
- ensureCapacityInternal(int minCapacity)
- 调用了 calculateCapacity 方法,是空数组{} 则返回默认容量 10 ,否则 返回最小容量, 即 add 方法中传入的 size+1
- 调用了 ensureExplicitCapacity 方法,如果 最小容量 大于 数组长度,则需要调用 gorw 方法扩容;否则 啥都不做,退回到 add 方法。
- grow(int minCapacity)
- 原数组长度 oldCapacity
- 新数组 newCapacity 长度为 oldCapacity + (oldCapacity >> 1),相当于 oldCapacity 的 1.5 倍。
- 判断 newCapacity 是否小于最小容量,是则设为最小容量。
- 判断 newCapacity 是否超过最大容量 MAX_ARRAY_SIZE,否则调用 hugeCapacity 方法。
- 根据新容量,复制新数组,实现扩容。
- hugeCapacity(int minCapacity) 根据 最小容量minCapacity 来 最大化 容量,超过 MAX_ARRAY_SIZE 则返回 Integer.MAX_VALUE,否则 返回 MAX_ARRAY_SIZE
值得注意的是, newCapacity 扩大为 oldCapacity 的 1.5 倍后,有可能溢出变成负数,此时
- 使用 newCapacity - minCapacity > 0 的判断,newCapacity - minCapacity 会溢出又变成正数,判断为 false,可以进入下个溢出判断。
- 但如果使用 newCapacity < minCapacity 则为 true,直接修改溢出不符合本身的逻辑。
最终结果是,不论是否溢出,都会保证newCapacity为正数。
总结一下:
- 空数组 扩容为 10
- 非空数组扩容为原容量的1.5倍
- 仍不满足最小容量,扩容为最小容量。如容量1扩容1.5倍也为1
- 扩容后溢出,根据 最小容量的值 ,扩容为 Integer.MAX_VALUE 或 MAX_ARRAY_SIZE;
数组进行扩容后,会将老数组中的元素重新拷贝一份到新的数组中,使用的是新的内存空间,这种操作的代价是很高的,应该尽量避免数组容量的扩张。指定其容量,或者手动扩容。
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;
}
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);
}
private static int hugeCapacity(int minCapacity) {
if (minCapacity < 0) // overflow
throw new OutOfMemoryError();
return (minCapacity > MAX_ARRAY_SIZE) ?
Integer.MAX_VALUE :
MAX_ARRAY_SIZE;
}
复制代码
4.手动扩容
同自动扩容的默认扩容策略,扩容为 1.5倍,若仍小于手动设置的扩容容量,则设为手动设置的大小。手动扩容的效率更高,且可以根据情况扩容,不浪费内存空间。
public void ensureCapacity(int minCapacity) {
int minExpand = (elementData != DEFAULTCAPACITY_EMPTY_ELEMENTDATA)
// any size if not default element table
? 0
// larger than default for default empty table. It's already
// supposed to be at default size.
: DEFAULT_CAPACITY;
if (minCapacity > minExpand) {
ensureExplicitCapacity(minCapacity);
}
}
复制代码
5 调整容量为当前实际大小
public void trimToSize() {
modCount++;
if (size < elementData.length) {
elementData = (size == 0)
? EMPTY_ELEMENTDATA
: Arrays.copyOf(elementData, size);
}
}
复制代码
2 Vector
3 LinkedList
LinkedList 同时实现了 List 接口和 Deque 接口,也就是说它既可以看作一个顺序容器,又可以看作一个队列 ( Queue ),同时又可以看作一个栈(Stack)。而且包含了队列、双向队列的一些方法。
LinkedList没有实现同步(synchronized),如果需要线程并发访问,可以采用Collections.synchronizedList()
方法对其进行包装。
1 底层数据结构
是一个双向链表,头结点 first、尾节点 last、元素数量 size。
transient int size = 0;
transient Node<E> first;
transient Node<E> last;
复制代码
Node 是私有内部类
private static class Node<E> {
E item;
Node<E> next;
Node<E> prev;
Node(Node<E> prev, E element, Node<E> next) {
this.item = element;
this.next = next;
this.prev = prev;
}
}
复制代码
2 构造方法
public LinkedList() {
}
public LinkedList(Collection<? extends E> c) {
this();
addAll(c);
}
复制代码
3 定位方法
对于定位 索引index位置上的节点,使用 index < (size >> 1) 进行判断,离 first 和 last 哪边更近,从哪边开始遍历。
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;
}
}
复制代码
包含 Queue 方法
// Queue operations.
/**
* Retrieves, but does not remove, the head (first element) of this list.
*
* @return the head of this list, or {@code null} if this list is empty
* @since 1.5
*/
public E peek() {
final Node<E> f = first;
return (f == null) ? null : f.item;
}
/**
* Retrieves, but does not remove, the head (first element) of this list.
*
* @return the head of this list
* @throws NoSuchElementException if this list is empty
* @since 1.5
*/
public E element() {
return getFirst();
}
/**
* Retrieves and removes the head (first element) of this list.
*
* @return the head of this list, or {@code null} if this list is empty
* @since 1.5
*/
public E poll() {
final Node<E> f = first;
return (f == null) ? null : unlinkFirst(f);
}
/**
* Retrieves and removes the head (first element) of this list.
*
* @return the head of this list
* @throws NoSuchElementException if this list is empty
* @since 1.5
*/
public E remove() {
return removeFirst();
}
/**
* Adds the specified element as the tail (last element) of this list.
*
* @param e the element to add
* @return {@code true} (as specified by {@link Queue#offer})
* @since 1.5
*/
public boolean offer(E e) {
return add(e);
}
复制代码
包含 Deque 方法
// Deque operations
/**
* Inserts the specified element at the front of this list.
*
* @param e the element to insert
* @return {@code true} (as specified by {@link Deque#offerFirst})
* @since 1.6
*/
public boolean offerFirst(E e) {
addFirst(e);
return true;
}
/**
* Inserts the specified element at the end of this list.
*
* @param e the element to insert
* @return {@code true} (as specified by {@link Deque#offerLast})
* @since 1.6
*/
public boolean offerLast(E e) {
addLast(e);
return true;
}
/**
* Retrieves, but does not remove, the first element of this list,
* or returns {@code null} if this list is empty.
*
* @return the first element of this list, or {@code null}
* if this list is empty
* @since 1.6
*/
public E peekFirst() {
final Node<E> f = first;
return (f == null) ? null : f.item;
}
/**
* Retrieves, but does not remove, the last element of this list,
* or returns {@code null} if this list is empty.
*
* @return the last element of this list, or {@code null}
* if this list is empty
* @since 1.6
*/
public E peekLast() {
final Node<E> l = last;
return (l == null) ? null : l.item;
}
/**
* Retrieves and removes the first element of this list,
* or returns {@code null} if this list is empty.
*
* @return the first element of this list, or {@code null} if
* this list is empty
* @since 1.6
*/
public E pollFirst() {
final Node<E> f = first;
return (f == null) ? null : unlinkFirst(f);
}
/**
* Retrieves and removes the last element of this list,
* or returns {@code null} if this list is empty.
*
* @return the last element of this list, or {@code null} if
* this list is empty
* @since 1.6
*/
public E pollLast() {
final Node<E> l = last;
return (l == null) ? null : unlinkLast(l);
}
/**
* Pushes an element onto the stack represented by this list. In other
* words, inserts the element at the front of this list.
*
* <p>This method is equivalent to {@link #addFirst}.
*
* @param e the element to push
* @since 1.6
*/
public void push(E e) {
addFirst(e);
}
/**
* Pops an element from the stack represented by this list. In other
* words, removes and returns the first element of this list.
*
* <p>This method is equivalent to {@link #removeFirst()}.
*
* @return the element at the front of this list (which is the top
* of the stack represented by this list)
* @throws NoSuchElementException if this list is empty
* @since 1.6
*/
public E pop() {
return removeFirst();
}
/**
* Removes the first occurrence of the specified element in this
* list (when traversing the list from head to tail). If the list
* does not contain the element, it is unchanged.
*
* @param o element to be removed from this list, if present
* @return {@code true} if the list contained the specified element
* @since 1.6
*/
public boolean removeFirstOccurrence(Object o) {
return remove(o);
}
/**
* Removes the last occurrence of the specified element in this
* list (when traversing the list from head to tail). If the list
* does not contain the element, it is unchanged.
*
* @param o element to be removed from this list, if present
* @return {@code true} if the list contained the specified element
* @since 1.6
*/
public boolean removeLastOccurrence(Object o) {
if (o == null) {
for (Node<E> x = last; x != null; x = x.prev) {
if (x.item == null) {
unlink(x);
return true;
}
}
} else {
for (Node<E> x = last; x != null; x = x.prev) {
if (o.equals(x.item)) {
unlink(x);
return true;
}
}
}
return false;
}
复制代码