Java容器框架提供了多種不一樣特性的容器方便咱們管理任意數量的對象。java
11.1泛型和類型安全的容器編程
JavaSE5以前的容器容許咱們向其中放入不一樣類型的對象,可是取出的時候須要進行類型強制轉換,很容易出現問題。有了泛型以後須要咱們只能向集合裏添加指定類型及其子類,取出時也不須要類型轉換,這個功能是編譯器完成的。數組
11.2基本概念安全
Java中容器分爲2個概念:併發
1)Collection:一個獨立元素的序列,這些元素都服從一條或多條規則。List必須按照插入順序保存元素,Set不能有重複元素。Queue按照排隊規則肯定對象產生的順序(一般與插入順序相同)。框架
2)Map:映射表容許咱們使用另外一個對象來查找某個對象,它也被稱爲關聯數組。性能
理想狀況下在建立對象時向上轉型成接口,方便切換實現,除非須要用到特有方法。測試
11.3添加一組元素優化
java.util包裏Arrays和Collections類有不少實用方法,能夠在一個Collection裏添加一組元素。spa
Arrays.asList()接受一個數組或者可變長參數,轉換成一個固定長度(不能add)的list。
Collections.addAll()接受一個Collection對象和一個可變長參數,向Collection裏添加一組元素。
Collection.addAll()只能接收一個Collection對象,沒有上面靈活。
首選:Collections.addAll()
注意Arrays.asList()對產生的List類型作了最理想的假設:即最近公共父類,這可能會產生問題。
好比:父類Person,一級子類Man,二級子類WhiteMan、BlackMan
List<Person> list = Arrays.asList(new WhiteMan(),new BlackMan());
這時會編譯出錯,由於編譯器找到理想的類型是List<Man>而不是List<Person>,咱們須要手動指定asList類型:
List<Person> list = Arrays.<Person>asList(new WhiteMan(),new BlackMan());
使用Collections.addAll()不須要指定類型,由於第一個參數裏已經有類型了。
11.4容器的打印
容器類不須要作特殊處理便可直接打印,而且能夠生成格式很好的輸出。
11.5List
List能夠把元素維護在特定的序列裏,在Collection基礎上添加了不少操做index的方法,如獲取,設置,插入,刪除。contains()/remove()/indexOf()等行爲是根據equals()結果來的。
ArrayList提供高效訪問,低效插入刪除。LinkedList相反,通常狀況使用ArrayList除非進行大量插入刪除使用ArrayList影響性能了才改用LinkedList。
subList()能夠返回大List裏的一個子List,至關於對象引用copy了一份,因此list.containsAll(subList)是true,對subList元素的操做也會影響原來的list。
retainAll()交集操做,保留兩個list裏的共同元素,基於equals()。
其餘方法...
11.6迭代器
任何容器都必須有某種方式能夠插入元素並把它取回。對於List能夠用get取出,若是從更高層次思考,會發現要使用容器,必須對容器的確切類型編程。若是咱們可使得對List使用的代碼也能夠對Set使用,就會很是方便。迭代器Iterator就是用於這種目的,使得咱們不須要關心序列的底層結構就可使用next()、hasNext()、remove()來遍歷或刪除序列中的元素。若是隻是遍歷不須要修改List,使用foreach更加方便。
remove()用了刪除最後一次next()獲得的元素,因此必須先使用next()取得元素,而後才能remove()
11.6.1ListIterator
是一個更增強大的Iterator子類型,但只能用於List類型的訪問。容許進行雙向(先後)訪問,可使用set替換被訪問的最後一個元素,能夠用listIterator(n)重載方法建立一個一開始就指向索引爲n的ListIterator.
11.7LinkedList
LinkedList相比ArrayList除了某些操做性能不一樣以外,還添加了可使其用做棧,隊列或雙端隊列的方法。不少方法名稱不一樣可是做用差很少,主要用於在不一樣上下文環境下使用。如element() getFirst(),remove(),removeFirst(),peek(),pop()等。
11.8Stack
後進先出,就像彈夾同樣的儲存裝置。LinkedList有實現棧功能的全部方法,能夠直接做爲棧使用,可是有時候用一個真正的棧更能夠把問題解決清楚優雅。
Java中提供了java.util.Stack類用於模擬一個Stack,可是設計的並不恰當:
1)Stack從Vector繼承而來,多了不少沒必要要的方法,並且有的方法會破壞Stack的規則:如add(index,obj)
2)Vector是數組實現的,在push()pop()時候效率很低,應該使用鏈式結構
咱們能夠本身寫一個:
public class Stack<T>{
private LinkedList<T> list = new LinkedList<>();
public void push(T t){list.addFirst(t);}
public T peek(){return list.getFirst();}
public T pop(){return list.removeFirst();}
public boolean empty(){return list.isEmpty();}
public String toString(){return list.toString();}
}
11.9Set
Set不保存重複的元素,最經常使用的功能就是測試是否包含對象,所以查找就成爲了Set中最重要的操做,HashSet實現專門對快速查找進行了優化。
Set與Collection接口徹底一致,只是行爲不一樣(多態的特性)。Set是根據對象的值來決定歸屬性的。
11.10Map
把對象映射到其它對象的能力是解決不少問題的殺手鐗。
遍歷時能夠返回鍵的set或者鍵值對的set
11.11Queue
隊列是典型的先進先出FIFO容器,取出順序與放入順序一致。是一種可靠的把對象從程序的某個區域傳輸到另外一個區域的途徑。在併發編程中特別重要。
LinkedList提供了方法能夠支持隊列行爲,而且也實現了Queue接口,因此它能夠用做Queue的一種實現。
Queue<Integer> q = new LinkedList<>();
offer():插入隊尾或返回false
peek()/element()返回隊頭,隊列爲空時peek返回null,element拋出NoSuchElementException
poll()/remove()返回隊頭並移除,隊列爲空時pool返回null,remove拋出NoSuchElementException
11.11.1PriorityQueue
隊列規則:給定一組隊列元素,肯定下一個彈出元素的規則。先進先出是典型的一種隊列規則。
優先級隊列聲明下一個彈出元素是優先級最高的元素。PriorityQueue在JavaSE5開始出現,默認元素順序是按照天然順序彈出,能夠設置一個Comparator來控制這種優先級。
11.12Collection和Iterator
實現Collection接口就必須提供建立Iterator的方法,保證了通用能力。
11.13ForEach與迭代器
任何實現了Iterable接口的類,均可以在foreach中使用。數組和Collection類均可以使用。但Map不行。
11.13.1適配器方法慣用法
使用不一樣的方法產生不一樣的Iterator,用於不一樣的迭代方式。
11.14總結
Java提供了大量持有對象的方式:
1.數組,保存單一類型對象,能夠是多維的,能夠保存基本類型,可是容量不可變。
2.Collection保存單一元素,Map保存鍵值對。有了泛型不須要進行類型轉換,不可持有基本類型可是會自動包裝來處理,容量可變。
3.List也創建了數字和對象的關聯,因此數組和List都是排序好的容器。List能自動擴容
4.大量隨機訪問用ArrayList,常常中間插入刪除用LinkedList。
5.隊列以及堆棧行爲用LinkedList完成。
6.Map是一種將對象與對象相關聯的設計。HashMap用於快速訪問,TreeMap保持鍵始終處於排序狀態,沒有HashMap快。LinkedHashMap保持元素插入順序,可是也經過散列提供了快速訪問的能力。
7.Set不接受重複元素。HashSet提供最快查詢速度,TreeSet保持元素處於排序狀態,LinkedHashSet以插入順序保存元素,查詢也快。
8.不該該使用過期的Vector(同步效率慢,擴容時候翻倍ArrayList擴一半),HashTable(同步效率慢),Stack
集合框架圖: