一、接口的API
1、Collection<E>
int size();
boolean isEmpty();
boolean contains(Object o);
Iterator<E> iterator();
Object[] toArray();
<T> T[] toArray(T[] a);//?
boolean add(E e);
boolean remove(Object o);
boolean containsAll(Collection<?> c);
boolean addAll(Collection<? extends E> c);
boolean removeAll(Collection<?> c);
boolean retainAll(Collection<?> c);//取交集
void clear();
boolean equals(Object o);
int hashCode();
2、List<E>
boolean addAll(int index, Collection<? extends E> c);
E get(int index);
E set(int index, E element);
void add(int index, E element);
E remove(int index);
int indexOf(Object o);
int lastIndexOf(Object o);
ListIterator<E> listIterator();
ListIterator<E> listIterator(int index);
List<E> subList(int fromIndex, int toIndex);
List接口繼承與Collection接口。由上可見,List相比於Collection,額外提供的方法均與index有關。即List是一個有序集合,內部的每一個元素都可以通過下標直接定位。
3、Set<E>
Set提供的方法與Collection完全一致。Set規範:元素不可重複。
4、SortedSet<E>
Comparator<? super E> comparator();
SortedSet<E> subSet(E fromElement, E toElement);
SortedSet<E> headSet(E toElement);
SortedSet<E> tailSet(E fromElement);
E first();
E last();
顧名思義,有序的Set。但與LinkedHashSet不同的是,前者通過Comparator比較元素的大小來進行排序,後者則是維護元素的插入順序。
SortedSet的這種維護是時刻維護的(就跟堆維護堆序一樣),每次插入元素的時候就會根據其大小放入合適的位置。
實現類有TreeSet。
5、Queue<E>
boolean add(E e);
boolean offer(E e);
E remove();
E poll();
E element();
E peek();
隊列:先進先出。注意,這裏的“進”並不一定是按照時間順序來衡量,有可能是按照其他順序來模擬時間上的先後。
|
拋出異常 |
返回特殊值 |
插入 |
||
移除 |
||
檢查 |
6、Deque<E>
void addFirst(E e);
void addLast(E e);
boolean offerFirst(E e);
boolean offerLast(E e);
E removeFirst();
E removeLast();
E pollFirst();
E pollLast();
E getFirst();
E getLast();
E peekFirst();
E peekLast();
boolean removeFirstOccurrence(Object o);
boolean removeLastOccurrence(Object o);
boolean add(E e);
boolean offer(E e);
E remove();
E poll();
E element();
E peek();
void push(E e);
E pop();
boolean remove(Object o);
boolean contains(Object o);
public int size();
Iterator<E> iterator();
Iterator<E> descendingIterator();
繼承於Queue,是一個雙向隊列。
二、實現類
1、ArrayList<E>
public class ArrayList<E> extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable
1、ArrayList存儲元素的數據結構實際上是一個數組,數組本身的大小是不可變的。因此,在向ArrayList中插入元素時,如果滿足觸發條件,會將ArrayList進行擴容。擴容後的數組大小通常滿足:newCapacity = oldCapacity + (oldCapacity >> 1);
2、ArrayList是有最大存儲容量的:
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
private static int hugeCapacity(int minCapacity) {
if (minCapacity < 0) // overflow
throw new OutOfMemoryError();
return (minCapacity > MAX_ARRAY_SIZE) ?
Integer.MAX_VALUE :
MAX_ARRAY_SIZE;
}
3、modCount??
4、在刪除ArrayList中的元素後,將數組的後邊的元素置爲null,以使GC回收,避免內存泄漏。如:
public void clear() {
modCount++;
// clear to let GC do its work
for (int i = 0; i < size; i++)
elementData[i] = null;
size = 0;
}
5、ArrayList中對數組的操作是通過System類的
public static native void arraycopy(Object src, int srcPos,
Object dest, int destPos, int length);
執行的。
6、迭代器
7、線程不安全舉例以及解決方案見Vector思考2.
2、LinkedList<E>
public class LinkedList<E>
extends AbstractSequentialList<E>
implements List<E>, Deque<E>, Cloneable, java.io.Serializable
LinkedList實現了Deque接口,是一個雙向隊列。
1、LinkedList的實現是建立在內部靜態類
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、LinkedList是有序的,而且是雙向的,可以儲存重複的元素,甚至是多個null。
3、學習LinkedList的源碼,發現在向LinkedList中插入、刪除元素時,需時刻注意操作前後相鄰兩個元素關係的維護,避免“鏈子”斷掉。對於每一個節點,不僅要維護自己的next,還要維護自己的prev。同時還要注意當前節點的next或者prev是不是null。
4、注意,向LinkedList中插入null時,只代表這個Node的item屬性是null,而這個Node卻一定不是null。其實,LinkedList這條由Node串聯起來的“鏈條”根本不存在爲null的Node,但是存在爲Null的元素(元素只是Node的item屬性)。
5、LinkedList實現了List接口,因此支持按index進行的元素的操作,但他沒有實現RandomAccess,也就是說它不支持隨機訪問,它的按index操作實際是通過由鏈條的兩端向中間一個一個訪問實現的。
6、LinkedList實現了Deque接口,因此同時具備隊列的特點,支持poll(),offer()等方法。
7、迭代器:實現很簡單,看源碼就行。
3、Vector<E>
public class Vector<E>
extends AbstractList<E>
Implements List<E>, RandomAccess, Cloneable, java.io.Serializable
1、Vector與ArrayList實現的接口完全一致。推斷功能也會類似。
2、Vector的擴容:
int newCapacity = oldCapacity + ((capacityIncrement > 0) ?
capacityIncrement : oldCapacity);
如果沒指定擴容參數,每次自動擴充一倍。
3、Vector的方法大部分被synchronized 修飾,因此Vector是線程安全的。
思考:1:ArrayList與Vector的區別在哪?
Vector是線程安全的,因此性能較低,已逐漸被棄用;而ArrayList是線程不安全的,但性能比Vector高。Vector每次擴容一倍,而ArrayList每次擴容一半。
思考2:ArrayList線程不安全舉例,如何解決?
ArrayList線程不安全舉例:
package com.lv.Number;
import java.util.ArrayList;
import java.util.List;
public class ArrayListInThread implements Runnable {
// 線程不安全
private List<String> threadList = new ArrayList<String>();
// 線程安全
// private List<string> threadList = Collections.synchronizedList(new
// ArrayList<string>());
@Override
public void run() {
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
// 把當前線程名稱加入list中
threadList.add(Thread.currentThread().getName());
}
public static void main(String[] args) throws InterruptedException {
ArrayListInThread listThread = new ArrayListInThread();
for (int i = 0; i < 100; i++) {
Thread thread = new Thread(listThread, String.valueOf(i));
thread.start();
}
// 等待子線程執行完
Thread.sleep(2000);
System.out.println(listThread.threadList.size());
// 輸出list中的值
for (int i = 0; i < listThread.threadList.size(); i++) {
if (listThread.threadList.get(i) == null) {
System.out.println();
}
System.out.print(listThread.threadList.get(i) + " ");
}
}
}
解決方式:private List<string> threadList = Collections.synchronizedList(new
ArrayList<string>());
public static <T> List<T> synchronizedList(List<T> list) {
return (list instanceof RandomAccess ?
new SynchronizedRandomAccessList<>(list) :
new SynchronizedList<>(list));
}
4、Stack<E>
public
class Stack<E> extends Vector<E>
基於Vector擴充實現了一個棧(後進先出)的數據結構。同時也具備Vector(動態數組)的功能。
5、HashSet
public class HashSet<E>
extends AbstractSet<E>
implements Set<E>, Cloneable, java.io.Serializable
基於HashMap類。
6、LinkedHashSet
基於LinkedHashMap類。
7、TreeSet
基於TreeMap類。