先來看幾道題目:java
public static void main(String[] args) { Set<String> set = new HashSet<String>(); set.add("Java"); set.add("JEE"); set.add("Spring"); set.add("Hibernate"); set = Collections.unmodifiableSet(set); set.add("Ajax"); // not allowed. }
能夠看到,建立不可變集合主要是調用了Collections的unmodifiableSet()方法,而Collections類經過裝飾模式實現了對通常集合的封裝。面試
public static void main(String args[]) { List<String> list=new ArrayList(); list.add("A"); list.add("B"); list.add("C"); list.add("A"); // List中容許元素重複 for(int i=0;i<list.size();i++) System.out.print(" "+list.get(i));// A B C A // 去除重複的元素且保持原有元素的順序 List list2=new testD().function(list); for(int i=0;i<list2.size();i++) System.out.print(" "+list2.get(i));// A B C } public <e> List<e> function (List<e> list) { return new ArrayList<e>(new LinkedHashSet<e>(list)); }
上面的代碼代碼經過把原有列表傳入一個LinkedHashSet來去除重複的元素。在這個狀況裏,LinkedHashSet能夠保持元素原來的順序。若是這個順序是不須要的話,那麼上面的LinkedHashSet能夠用HashSet來替換。數組
其實如上的兩道題目並不難,只是沒有對集合瞭解的更深。下面就來大概的看一下集合吧。集合的繼承類以下所示。框架
如上的集合能夠概括爲三大類,即List、Set和Map。同時還有一些輔助的工具類,像Collections、Arrays等方便了集合的操做,各個集合的比較狀況以下圖。函數
其實對於集合的操做,無外乎就是工具
從Java集合框架圖能夠看出,全部的類都直接或間接繼承了Iterable接口,源代碼以下:this
package java.lang; import java.util.Iterator; /** * Implementing this interface allows an object to be the target of * the "foreach" statement. */ public interface Iterable<T> { Iterator<T> iterator(); // 返回一個在一組 T 類型的元素上進行迭代的迭代器 }
Iterable接口在java.lang包下,其中定義了一個獲取Iterator的實例方法。spa
Iterator類的源代碼以下:.net
public interface Iterator<E> { boolean hasNext(); // 是否含有下一個元素 E next(); // 獲取集合的下一個元素 void remove(); // 從集合中移除當前元素 }
Iterator模式是用於遍歷集合類的標準訪問方法。它能夠把訪問邏輯從不一樣類型的集合類中抽象出來,從而避免向客戶端暴露出集合的內部結構。例如,若是沒有使用Iterator,遍歷一個數組的方法是使用索引: 設計
for(int i=0; i<集合的大小;i++){ // 省略操做代碼 }
當訪問一個鏈表(LinkedList)時又必須使用while循環:
while((e=e.next())!=null) { // 省略操做代碼 }
以上兩種方法遍歷辦法都必須事先知道集合的內部存儲結構,訪問代碼和集合自己是緊耦合,沒法將訪問邏輯從集合類中分離出來,每一種集合對應一種遍歷方法,客戶端代碼沒法複用。 並且若是之後須要把ArrayList更換爲LinkedList,則原來的客戶端代碼必需要進行重寫。 爲解決以上問題,Iterator模式老是用同一種邏輯來遍歷集合:
for(Iterator it = c.iterater();it.hasNext(); ) { // ... }
設計的巧妙之處在於客戶端自身不維護遍歷集合的"指針",全部的內部狀態(如當前元素位置,是否有下一個元素)都由Iterator來維護,而這個Iterator由集合類經過工廠方法生成,所以,它知道如何遍歷整個集合。值得提醒的是,這個工廠方法就是咱們前面提到的iterator()方法,由於全部的類都繼承了Iterable接口,因此他的實現類必需要實現iterator()方法。
之後若是要訪問集合時,就能夠經過控制Iterator,向它發送"向前","向後","取當前元素"的命令,來間接遍歷整個集合。
舉例以下:
public class testSet { public static void main(String args[]) { // HashSet<String> ct = new HashSet<>(); // Set<String> ct=new HashSet<>(); // List<String> ct=new ArrayList<>(); List<String> ct=new LinkedList<>(); ct.add("abc"); ct.add("def"); for(Iterator<String> myitr = ct.iterator();myitr.hasNext();){ System.out.println(myitr.next()); } Iterator<String> iter = ct.iterator(); while (iter.hasNext()) { System.out.println(iter.next()); } for (String str : ct) { System.out.println(str); } } }
使用了3種方法進行集合的遍歷,輸出的結果都是一致的,以下:
abc
def
abc
def
abc
def
每一種集合類返回的Iterator具體類型可能不一樣,Array可能返回ArrayIterator,Set可能返回 SetIterator,Tree可能返回TreeIterator,可是它們都實現了Iterator接口,所以,客戶端不關心究竟是哪一種 Iterator,它只須要得到這個Iterator接口便可,這就是面向對象所帶來的好處。
查看各個集合的Iterator具體實現地址以下:
傳送門一、http://blog.csdn.net/mazhimazh/article/details/17759579
傳送門二、http://blog.csdn.net/mazhimazh/article/details/17835467
繼續看Collection接口,源代碼以下:
public interface Collection<E> extends Iterable<E> { // 查找操做 int size(); Iterator<E> iterator(); // 判斷 boolean isEmpty(); boolean contains(Object o); boolean containsAll(Collection<?> c); // 增長操做 boolean add(E e); boolean addAll(Collection<? extends E> c); // 刪除操做 boolean remove(Object o); boolean removeAll(Collection<?> c);// Removes all of this collection's elements that are also contained in the specified collection (optional operation). boolean retainAll(Collection<?> c);// Retains only the elements in this collection that are contained in the specified collection (optional operation). void clear(); // 集合轉換 Object[] toArray(); <T> T[] toArray(T[] a); // 提供equals()和hashCode() boolean equals(Object o); int hashCode(); }
Collection接口針對集合定義了一些基本的操做,因此任何一個具體的集合實現類都有含有這些方法。可是因爲抽象層次較高,因此通常一個具體 的集合實現類,如ArrayList、HashMap等都不會直接繼承這個接口,而是繼承這個接口的一些子類來實現。因此說每一個集合的具體實現類都直接或 間接繼承了這個接口。
有一類重要的方法還須要說明一下:
boolean add(E e); boolean addAll(Collection<? extends E> c); boolean remove(Object o); boolean removeAll(Collection<?> c);
拿add(E e)方法來舉例,這個方法將在集合中添加一個新的元素。方法會返回一個boolean,可是返回值不是表示添加成功與否。 仔細閱讀doc能夠看到,Collection規定:若是一個集合拒絕添加這個元素,不管任何緣由,都必須拋出異常。這個返回值表示的意義是add()方 法執行後,集合的內容是否改變了(就是元素有無數量,位置等變化),這是由具體類實現的。即:若是方法出錯,總會拋出異常;返回值僅僅表示該方法執行後這 個Collection的內容有無變化。
觀察發現傳入的參數有許多都是Collection<?>類型的,這就爲各個集合的具體實現類實現相互的操做提供了便利。舉個例子:
LinkedList<String> list=new LinkedList<>(); list.add("xy"); list.add("mn"); Collection<String> ct=new HashSet<String>(); ct.add("abc"); ct.add("def"); ct.addAll(list); Iterator<String> iter=ct.iterator(); while(iter.hasNext()){ System.out.println(iter.next()); }
將LinkedList集合中的元素添加到HashSet中,只須要調用addAll()方法便可。最後結果輸出以下:
mn
abc
def
xy
1 Collection是一個接口,是高度抽象出來的集合,它包含了集合的基本操做和屬性。
Collection包含了List和Set兩大分支。
(01) List是一個有序的隊列,每個元素都有它的索引。第一個元素的索引值是0。
List的實現類有LinkedList, ArrayList, Vector, Stack。
(02) Set是一個不容許有重複元素的集合。
Set的實現類有HastSet和TreeSet。HashSet依賴於HashMap,它其實是經過HashMap實現的;TreeSet依賴於TreeMap,它其實是經過TreeMap實現的。
2 Map是一個映射接口,即key-value鍵值對。Map中的每個元素包含「一個key」和「key對應的value」。
AbstractMap是個抽象類,它實現了Map接口中的大部分API。而HashMap,TreeMap,WeakHashMap都是繼承於AbstractMap。
Hashtable雖然繼承於Dictionary,但它實現了Map接口。
接下來,再看Iterator。它是遍歷集合的工具,即咱們一般經過Iterator迭代器來遍歷集合。咱們說Collection依賴於Iterator,是由於Collection的實現類都要實現iterator()函數,返回一個Iterator對象。
ListIterator是專門爲遍歷List而存在的。
再看Enumeration,它是JDK 1.0引入的抽象類。做用和Iterator同樣,也是遍歷集合;可是Enumeration的功能要比Iterator少。在上面的框圖 中,Enumeration只能在Hashtable, Vector, Stack中使用。
最後,看Arrays和Collections。它們是操做數組、集合的兩個工具類。