集合系列

一、關於集合的兩道面試題

先來看幾道題目: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類經過裝飾模式實現了對通常集合的封裝。面試

二、去除List集合中的重複元素,且保持原有的順序

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等方便了集合的操做,各個集合的比較狀況以下圖。函數

其實對於集合的操做,無外乎就是工具

  1. 增長:向一個集合中添加一個元素、將一個集合中的全部元素插入到當前集合中
  2. 刪除:刪除指定的一個元素、刪除集合中全部的元素
  3. 修改:修改指定的一個元素
  4. 查找:查當前集合的大小、查找兩個集合中的共同元素等
  5. 其它:如將一個集合中的元素轉換爲數組表示形式、判斷一個集合是否爲空等

三、Iterable、Iterator、Collection接口

從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。它們是操做數組、集合的兩個工具類。

相關文章
相關標籤/搜索