一、ArrayList
1、ArrayList使用的数据结构
ArrayList底层使用数组,数组是一块内存中连续的空间,数组,用于顺序存储数据,每一个数据都有一个对应的下标,可以通过下标唯一地获取数组中的数据。
在ArrayList实现中,查询效率比较高;添加和删除效率较低。
2、属性
private static final long serialVersionUID = 8683452581122892189L;
private static final int DEFAULT_CAPACITY = 10;
private static final Object[] EMPTY_ELEMENTDATA = {};
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
transient Object[] elementData;
private int size;
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
3、构造器
- 如果使用无参构造器,默认这个集合底层为一个空数组;
- 如果传入的是一个数字,那么会根据这个数字创建一个指定长度的数组;
- 如果传入的是一个集合,那就把集合转为数组,然后拷贝出一份赋值给elementData,如果集合是ArrayList的话,那么直接把引用给elementData。
public ArrayList() {
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
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(Collection<? extends E> c) {
Object[] a = c.toArray();
if ((size = a.length) != 0) {
if (c.getClass() == ArrayList.class) {
elementData = a;
}
else {
elementData = Arrays.copyOf(a, size, Object[].class);
}
}
else {
elementData = EMPTY_ELEMENTDATA;
}
}
4、add方法
add一个元素,先检查容量是否足够,不够就会去获取最小容量,如果是然后根据最小容量扩容,默认扩容是1.5倍。
并且,当集合的最小容量已经达到了Integer.MAX_VALUE - 8时,扩容将会是扩容至Integer.MAX_VALUE,这是集合最大容量。
public boolean add(E e) {
ensureCapacityInternal(size + 1);
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++;
if (minCapacity - elementData.length > 0)
grow(minCapacity);
}
private void grow(int minCapacity) {
int oldCapacity = elementData.length;
int newCapacity = oldCapacity + (oldCapacity >> 1);
if (newCapacity - minCapacity < 0)
newCapacity = minCapacity;
if (newCapacity - MAX_ARRAY_SIZE > 0)
newCapacity = hugeCapacity(minCapacity);
elementData = Arrays.copyOf(elementData, newCapacity);
}
private static int hugeCapacity(int minCapacity) {
if (minCapacity < 0)
throw new OutOfMemoryError();
return (minCapacity > MAX_ARRAY_SIZE) ?
Integer.MAX_VALUE :
MAX_ARRAY_SIZE;
}
在指定的index下去add元素,那会先判断index是否越界,然后判断是否需要扩容(1.5倍,最大为Integer.MAX_VALUE);
最后再指定index坐标以及其后的元素统一使用System.arrayCopy向后移动一位。
public void add(int index, E element) {
rangeCheckForAdd(index);
ensureCapacityInternal(size + 1);
System.arraycopy(elementData, index, elementData, index + 1,size - index);
elementData[index] = element;
size++;
}
private void rangeCheckForAdd(int index) {
if (index > size || index < 0)
throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}
5、remove方法
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);
elementData[--size] = null;
return oldValue;
}
E elementData(int index) {
return (E) elementData[index];
}
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;
}
6、为何迭代器迭代时,使用集合对象删除元素后会报错
static final class ArrayListSpliterator<E> implements Spliterator<E> {
private final ArrayList<E> list;
private int index;
private int fence;
private int expectedModCount;
}
二、Vector
1、基本介绍和底层数据结构
和ArrayList的API基本一致,底层的实现原理也是使用数组,只不过Vector是线程安全的,几乎所有的操作方法都有加synchronized关键字。
2、属性
protected Object[] elementData;
protected int elementCount;
protected int capacityIncrement;
private static final long serialVersionUID = -2767605614048989439L;
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
3、构造器
public Vector(int initialCapacity, int capacityIncrement) {
super();
if (initialCapacity < 0)
throw new IllegalArgumentException("Illegal Capacity: "+ initialCapacity);
this.elementData = new Object[initialCapacity];
this.capacityIncrement = capacityIncrement;
}
public Vector(int initialCapacity) {
this(initialCapacity, 0);
}
public Vector() {
this(10);
}
public Vector(Collection<? extends E> c) {
Object[] a = c.toArray();
elementCount = a.length;
if (c.getClass() == ArrayList.class) {
elementData = a;
} else {
elementData = Arrays.copyOf(a, elementCount, Object[].class);
}
}
4、add方法
public synchronized boolean add(E e) {
modCount++;
ensureCapacityHelper(elementCount + 1);
elementData[elementCount++] = e;
return true;
}
private void ensureCapacityHelper(int minCapacity) {
if (minCapacity - elementData.length > 0)
grow(minCapacity);
}
private void grow(int minCapacity) {
int oldCapacity = elementData.length;
int newCapacity = oldCapacity + ((capacityIncrement > 0) ?
capacityIncrement : oldCapacity);
if (newCapacity - minCapacity < 0)
newCapacity = minCapacity;
if (newCapacity - MAX_ARRAY_SIZE > 0)
newCapacity = hugeCapacity(minCapacity);
elementData = Arrays.copyOf(elementData, newCapacity);
}
private static int hugeCapacity(int minCapacity) {
if (minCapacity < 0)
throw new OutOfMemoryError();
return (minCapacity > MAX_ARRAY_SIZE) ?
Integer.MAX_VALUE :
MAX_ARRAY_SIZE;
}
5、copyInto方法
public synchronized void copyInto(Object[] anArray) {
System.arraycopy(elementData, 0, anArray, 0, elementCount);
}
三、LinkedList
1、基本介绍和底层数据结构
- LinkedList底层实现了双向链表和双端队列特点,是非顺序的存储结构,数据元素的逻辑顺序通过链表节点的指针连接实现;
- 链表是由一系列节点(链表中的元素称为节点)组成,节点可以在运行时动态生成,每个节点包括两个部分:存储数据的数据域,存储下一个节点指针的指针域;
- 双链表是链表的一种,由节点组成,每个节点有两个指针,分别指向直接前驱和直接后继节点;
- 可以添加任意元素元素还可以重复,可以为null;线程不安全,没有实现同步。
2、属性
transient int size = 0;
transient Node<E> first;
transient Node<E> last;
3、构造器
public LinkedList() {
}
public LinkedList(Collection<? extends E> c) {
this();
addAll(c);
}
4、私有静态内部Node类
节点,是链表的组成,LinkedList每一个数据都是存在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;
}
}
5、add方法
获取头节点,如果头节点本为null,那么就设置新节点为头节点;如果不是null,那就设置头节点为新节点,然后原头节点的前驱节点为新节点;
public void addFirst(E e) {
linkFirst(e);
}
private void linkFirst(E e) {
final Node<E> f = this.first;
final Node<E> newNode = new Node<>(null, e, f);
this.first = newNode;
if (f == null)
last = newNode;
else
f.prev = newNode;
size++;
modCount++;
}
直接add一个元素,本质就是添加节点到链表末尾;
public boolean add(E e) {
linkLast(e);
return true;
}
void linkLast(E e) {
final Node<E> l = this.last;
final Node<E> newNode = new Node<>(l, e, null);
this.last = newNode;
if (l == null)
first = newNode;
else
l.next = newNode;
size++;
modCount++;
}
指定一个下标增加元素,本质上是让指定的下标的节点的pre指针指向含有数据element的新节点,让指定的下标的节点的原直接前驱节点的next指针指向含有数据element的新节点。
public void add(int index, E element) {
checkPositionIndex(index);
if (index == size)
linkLast(element);
else
linkBefore(element, node(index));
}
private void checkPositionIndex(int index) {
if (!isPositionIndex(index))
throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}
private boolean isPositionIndex(int index) {
return index >= 0 && index <= size;
}
void linkBefore(E e, Node<E> succ) {
final Node<E> pred = succ.prev;
final Node<E> newNode = new Node<>(pred, e, succ);
succ.prev = newNode;
if (pred == null)
this.first = newNode;
else
pred.next = newNode;
size++;
modCount++;
}
Node<E> node(int 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 void addFirst(E e) {
linkFirst(e);
}
private void linkFirst(E e) {
final Node<E> f = this.first;
final Node<E> newNode = new Node<>(null, e, f);
this.first = newNode;
if (f == null)
this.last = newNode;
else
f.prev = newNode;
size++;
modCount++;
}
把指定集合内的元素全部添加进链表;
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)
this.first = newNode;
else
pred.next = newNode;
pred = newNode;
}
if (succ == null) {
this.last = pred;
}
else {
pred.next = succ;
succ.prev = pred;
}
size += numNew;
modCount++;
return true;
}
6、remove方法
删除链表中指定的元素。
public boolean remove(Object o) {
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;
}
E unlink(Node<E> x) {
final E element = x.item;
final Node<E> next = x.next;
final Node<E> prev = x.prev;
if (prev == null) {
this.first = next;
}
else {
prev.next = next;
x.prev = null;
}
if (next == null) {
this.last = prev;
}
else {
next.prev = prev;
x.next = null;
}
x.item = null;
size--;
modCount++;
return element;
}
根据指定的index删除这个index下的节点。
public E remove(int index) {
checkElementIndex(index);
return unlink(node(index));
}
3、get方法
指定下标获取数据。
public E get(int index) {
checkElementIndex(index);
return node(index).item;
}
4、iterator方法
返回一个ListItr类对象,List迭代器;
public Iterator<E> iterator() {
return listIterator();
}
public ListIterator<E> listIterator() {
return listIterator(0);
}
public ListIterator<E> listIterator(final int index) {
rangeCheckForAdd(index);
return new ListItr(index);
}
关于iterator方法返回的迭代器,是LinkedList下的一个私有内部类ListItr;
属性
private Node<E> lastReturned;
private Node<E> next;
private int nextIndex;
private int expectedModCount = modCount;
构造器
ListItr(int index) {
this.next = (index == size) ? null : node(index);
this.nextIndex = index;
}
next方法
public E next() {
checkForComodification();
if (!hasNext())
throw new NoSuchElementException();
this.lastReturned = next;
this.next = next.next;
this.nextIndex++;
return lastReturned.item;
}
final void checkForComodification() {
if (this.modCount != this.expectedModCount)
throw new ConcurrentModificationException();
}
hasNext方法
public boolean hasNext() {
return this.nextIndex < this.size;
}
|