前面咱們學習了Iterator、Collection,爲集合的學習打下了基礎,如今咱們來學習集合的第一大致系 List。數組
List 是一個接口,定義了一組元素是有序的、可重複的集合。安全
List 繼承自 Collection,較之 Collection,List 還添加了如下操做方法bash
AbstractList 繼承自 AbstractCollection 類,實現了 List 接口。整個類的設計相似於AbstractCollection,實現了大多數方法,抽象了對於須要根據數據操做的方法。數據結構
ArrayList 是咱們最經常使用的一個類,它具備以下特色:學習
從成員變量,咱們能夠得知ui
如今咱們知道了 ArrayList 其實就是基於數組的實現。所以,增刪改查操做就變得很容易理解了。this
這裏的操做很簡單,好比說含有8個元素的數組array,要在第五個位置插入一個元素x,則將第[5,8)角標的元素分別日後移動一位變成[6,9),此時角標爲5的位置空出來,使 array[5] = x 便可。spa
如今咱們來看看擴容機制,假設咱們如今有一個集合 list,裏面正好含有10個元素,此時,咱們調用 add(object)方法添加一個元素,看看是怎樣執行擴容操做的。線程
public boolean add(E var1) {
//查看是數組長度是否夠
this.ensureCapacityInternal(this.size + 1);
this.elementData[this.size++] = var1;
return true;
}
private void ensureCapacityInternal(int var1) {
//檢查是不是默認長度爲0的數組,若是是則長度設爲10
if(this.elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
var1 = Math.max(10, var1);
}
this.ensureExplicitCapacity(var1);
}
private void ensureExplicitCapacity(int var1) {
++this.modCount;
//當前須要的長度大於數組長度,執行擴容操做
if(var1 - this.elementData.length > 0) {
this.grow(var1);
}
}
private void grow(int var1) {
int var2 = this.elementData.length;
//var3 = var2*1.5;擴容1.5倍
int var3 = var2 + (var2 >> 1);
if(var3 - var1 < 0) {
var3 = var1;
}
//新容量超出最大值
if(var3 - 2147483639 > 0) {
var3 = hugeCapacity(var1);
}
//從新建立了一個1.5倍容量的數組賦值給elementData
this.elementData = Arrays.copyOf(this.elementData, var3);
}複製代碼
從上面咱們能夠看到,修改某個角標的值或者查找某個角標的值時,咱們能夠直接調用數組的操做,效率很高。可是添加和刪除則是要操做整個數組的移動,效率稍低。設計
這裏咱們也能夠看到,其實 ArrayList 就是一個針對數組操做的封裝類。
剛剛咱們看了 ArrayList,ArrayList 的增刪操做效率相對較低。所以,Java 給咱們設計了另一種增刪效率比較高的集合 LinkedList。
LinkedList 繼承自 AbstractSequentialList。
AbstractSequentialList 又繼承自AbstractList,而且基於 iterator 實現了默認增刪改查操做。
再回過頭來看 LinkedList,LinkedList 還實現了Deque(雙向隊列)接口,雙向隊列後面咱們會單獨去學習,這裏再也不作過多的贅述。
再來看當作員變量~~
特色?和 ArrayList 的優缺點互補。
鏈表的實現,鏈表的實現很簡單,就是最基本的鏈表數據結構。理解鏈表數據結構能夠跳過這裏了。
我舉個例子吧,如今要讓 a、b、c、d 四個同窗按順序投籃。有兩種方法,第一種是 abcd 排成一個隊伍,依次去投籃;可是體育課上讓全部的同窗等着投籃很浪費時間,所以有了第二種辦法:依次告訴 a‘你投了藍以後叫 b 來投籃’,告訴 b‘你投了藍以後叫 c 來投籃’以此類推。
這樣,就造成了一個簡單的單向列表,abcd 按照順序依次去投籃。此時,x 同窗因爲身體不舒服須要提早投籃回教室休息,則老師只須要告訴 a 同窗投完籃以後不用叫 b 同窗了,改叫 x 同窗,x 同窗投完籃以後叫 b 同窗便可。
很少說了,新手聽不懂,老手用不上。不懂鏈表的同窗好好去學學數據結構吧。
後面的增刪改查操做就只是基礎的遍歷鏈表操做,就不去一一去讀源碼了,鏈表操做記不太清楚的同窗能夠去看一下 LinkedList 的源碼。
在學習了 ArrayList 以後,Vector 這個類我想用」線程安全的 ArrayList「能夠一句話歸納了。
Vector 和 ArrayList 同樣都繼承自 AbstractList,爲何說」Vector 是線程安全的 ArrayList「,原本還準備列個表讓你們對比一下成員變量以及主要操做方法的實現。but,除了 Vector 的方法上多了個 synchronized 外,代碼都是同樣的,比較個毛。所以,若是須要考慮線程安全,直接使用 Vector 便可,可是由於全部方法都加了synchronized ,效率相對會比較低,若是沒有線程安全的需求,那就使用 ArrayList 唄。
最後,仍是說一下Vector 和 ArrayList的區別吧,反正也沒什麼卵用,你們看看就好
爲了找到 Enumeration 這種迭代器有什麼特色,我去翻了一下 Vector 的代碼,找到了一個這樣的方法和這樣的接口,大家感覺一下。
public Enumeration<E> elements() {
return new Enumeration() {
int count = 0;
public boolean hasMoreElements() {
return this.count < Vector.this.elementCount;
}
public E nextElement() {
Vector var1 = Vector.this;
synchronized(Vector.this) {//區別在這裏
if(this.count < Vector.this.elementCount) {
return Vector.this.elementData(this.count++);
}
}
throw new NoSuchElementException("Vector Enumeration");
}
};
}
public interface Enumeration<E> {
boolean hasMoreElements();
E nextElement();
}複製代碼
mmp,這個 Enumeration 和Iterator 接口除了名字不同,還有什麼區別?而後仔細看了一遍,在elements()方法裏面的匿名內部了裏面找到了nextElement()方法裏面有個同步代碼塊。好吧, Enumeration 大概是線程安全的Iterator?
Stack 繼承自Vector,也是一個線程安全的集合。
Stack 也是基於數組實現的。
Stack 實現的是棧結構集合
數據結構中,棧也是一種線性的數據結構,遵照 LIFO(後進先出)的操做順序,這裏用一張很污的圖,保證大家看了以後能熟記棧結構特徵。
小時候確定都玩過羽毛球吧,羽毛球不經打,要常常換球,因而我買了一盒羽毛球,以下圖,就是一個羽毛球盒子,最早放進去的羽毛球(棧底的),要最後才能取出來。
類結構圖以下,代碼量也很少,一共才30幾行
public class Stack<E> extends Vector<E> {
private static final long serialVersionUID = 1224463164541339165L;
public Stack() {
}
//入棧,添加一個元素到數組的最後一個
public E push(E var1) {
this.addElement(var1);
return var1;
}
//出棧,刪除數組最後一個元素並返回
public synchronized E pop() {
int var2 = this.size();
Object var1 = this.peek();
this.removeElementAt(var2 - 1);
return var1;
}
//獲取最後一個元素,不刪除
public synchronized E peek() {
int var1 = this.size();
if(var1 == 0) {
throw new EmptyStackException();
} else {
return this.elementAt(var1 - 1);
}
}
public boolean empty() {
return this.size() == 0;
}
獲取棧中的 位置。
public synchronized int search(Object var1) {
int var2 = this.lastIndexOf(var1);
return var2 >= 0?this.size() - var2:-1;
}
}複製代碼
整個類的實現很是簡單,就是繼承 Vector,而後添加了 peek、pop、push、search 等方法,而後然添加刪除都在最末尾的元素作操做便可。
思考:怎樣用鏈表的結構快速實現 LinkedListStack?