1. 程式人生 > >Java(集合框架)

Java(集合框架)

一、集合框架(CollectionAPI)(資料處理
 

        集合類:面向物件對語言對事物的體現都是以物件的形式,所以為了方便對多個物件的操作,就是對物件進行儲存,集合就是儲存物件最常用的方式

  集合是一系列物件的聚集(Collection)(集合就是一個儲存一組物件的容器),集合在程式設計中是一種重要的資料介面。Java中提供了有關集合的類庫稱為CollectionAPI(Collection API中的介面和類主要唯一java.util包中

          集合實際上是用一個物件代表一組物件

,在集合中的每個物件稱為一個元素。在集合中的各個元素的具體型別可以不同,集合中只能儲存物件(儲存物件的引用變數)(陣列既可以儲存基本型別的資料也可以儲存物件), 當我們把一個物件放入集合中後,系統會把所有集合元素都當成Object類的例項進行處理。從JDK1.5以後,這種狀態得到了改進:可以使用泛型來限制集合裡元素的型別,並讓集合記住所有集合元素的型別

        集合類的特點:

        集合只用於儲存物件,集合的長度是可變的,集合可以儲存不同的型別的物件

        陣列和集合類同是容器,有何不同?

        陣列雖然也可以儲存物件,當長度是固定的,集合長度是可變的,陣列中可以儲存基本資料型別,集合只能儲存物件

         從集合框架圖中可以看出,分為兩類:以Collection為介面的元素集合型別,以Map為介面的對映集合型別

 

       

 


二、Collection介面及其子介面

          Collection介面(

CollectionAPI 最基本的介面)是將一組物件以集合元素的形式組織到一起,在其子介面中分別實現不同的組織方式(Set和List介面是Collection介面派生的兩個子介面)

         Collection介面(類集介面)List、Set和Queue介面的父介面,並且同時可以操作這三個介面,三個介面分別為:

                   List(列表介面):保持元素的特定的順序,且允許有重複元素

                   Set(資料集介面):不記錄元素的儲存順序,且不允許有重複元素(不常用)

                   Queue(佇列):提供的佇列實現,類似於List

           Set 介面的重用實現類有HashSet(雜湊集),List介面的重要實現類有ArrayList,LinkedList和Vector(向量類,以實現類似動態陣列的功能(被ArrayList代替)),它們的關係如下圖所示。

 

    

 

            (1) 單元素新增、刪除操作: 

                    boolean add(Object o):將物件新增給集合 

                    boolean remove(Object o): 如果集合中有與o相匹配的物件,則刪除物件o 

            (2) 查詢操作: 

                    int size() :返回當前集合中元素的數量 

                    boolean isEmpty() :判斷集合中是否有任何元素 

                    boolean contains(Object o) :查詢集合中是否含有物件o 

                    Iterator iterator() :返回一個迭代器,用來訪問集合中的各個元素 

            (3) 組操作 :作用於元素組或整個集合 

                    boolean containsAll(Collection c): 查詢集合中是否含有集合c 中所有元素 

                    boolean addAll(Collection c) : 將集合c 中所有元素新增給該集合 

                    void clear(): 刪除集合中所有元素 

                    void removeAll(Collection c) : 從集合中刪除集合c 中的所有元素 

                    void retainAll(Collection c) : 從集合中刪除集合c 中不包含的元素 

            (4) Collection轉換為Object陣列 : 

                    Object[] toArray() :返回一個內含集合所有元素的array 

                    Object[] toArray(Object[] a) :返回一個內含集合所有元素的array。執行期返回的array和引數a的型別相同,需要轉換為正確型別。 

               此外,還可以把集合轉換成其它任何其它的物件陣列。但是,您不能直接把集合轉換成基本資料型別的陣列,因為集合必須持有物件。Collection不提供get()方法。如果要遍歷Collectin中的元素,就必須用Iterator 

             Collection介面中重要的方法有:

                    public boolean add(Object o);         //新增元素

                    public boolean remove(Object o);         //移除元素

                    public void clear();         //清除所有元素

                    public boolean contains(Object o);         //判斷是否包含某元素

                    public int size();         //元素個數

                    public boolean isEmpty();         //判斷是否為空

                    public Iterator iterator();         //得到迭代器

 

    1.List介面(容器)

    List 介面繼承了 Collection 介面以定義一個允許重複項的有序集合(有序且可重複)

        在“集合框架”中有兩種常規的 List 介面實現類:ArrayList 和 LinkedList(連結串列)(ArrayList 和 LinkedList 都實現 Cloneable 介面,都提供了兩個建構函式,一個無參的,一個接受另一個Collection),使用兩種 List 中的哪一種取決於特定的需要( LinkedList內部封裝的是雙向連結串列的資料結構, 不同的資料有不同的資料結構,不同的資料結果操作起來效能不一樣,連結串列資料結構,做插入、刪除的效率高(可基於 LinkedList實現棧和佇列),但查詢效率低,而陣列結構(ArrayList),做查詢時效率高,但插入和刪除效率低(做移位操作)

   

class MyStack<T>{//實現棧的功能(後進先出),採用LinkedList的資料結構

     private LinkedList<T> data=null;

     public MyStack(){

         data=new LinkedList<T>();

    }

     //壓棧的方法

     public void push(T obj){

         data.addFirst(obj);

     }

     public T pop(){

         return data.removeFirst();

     }

     public Iterator<T> iterator(){//必須在該類中定義該方法

        return data. iterator();

     }

}

    2.Set介面(容器)

            Set 介面繼承 Collection 介面,基本與Collection方法相同,只是行為不同(Set不允許包含重複元素,並且最多包含一個null元素

Set集合不允許重複元素,是因為Set判斷兩個物件相同不是使用==運算子,而是根據equals方法。即兩個物件用equals方法比較返回true(不能新增到Set集合中)

 

  1. HashSet實現類(底層是雜湊表,不能確保元素順序

           HashSet的特點:

(1)HashSet不是同步的,多個執行緒訪問是需要通過程式碼保證同步
(2)集合元素值可以使null

    HashSet集合判斷兩個元素相等的標準是兩個物件通過equals方法比較相等,並且兩個物件的hashCode()方法返回值也相等

                LinkedHashSet(HashSet的子類)集合也根據元素hashCode值來決定元素儲存位置,但也同時使用連結串列維護元素的次序,即當遍歷LinkedHashSet集合元素時,HashSet將會按元素的新增順序來訪問集合裡的元素

 

    2. TreeSet實現類
                TreeSet是SortedSet介面的唯一實現,TreeSet可以確保集合元素處於排序狀態(元素是有序的)

               TreeSet的內部操作的底層資料時TreeMap(只是我們操作的是TreeMap的key)
}

public class TreeSetDemo1 {

     public static void main(String[] args) {

                       TreeSet<Person> pset = new TreeSet<Person>();

                       pset.add(new Person("zhangsan", 28));

                       pset.add(new Person("lisi", 18));

                       pset.add(new Person("wangwu", 25));

                       pset.add(new Person("zhaoliu", 14));

                      //System.out.println(pset);

                        // 打印出來

                      Iterator<Person> it = pset.iterator();//通過迭代器進行迭代

                      while (it.hasNext()) {//判斷是否有資料

                                Person p = it.next();//取出的是Person型別

                                System.out.println(p.getName()+"--"+p.getAge());

                           }

                     }

 

 

 

三、兩種遍歷集合的方法(Iterator介面和foreach迴圈

        1. Iterator介面

               Iterator介面也是Java集合框架的成員,主要用於遍歷(即迭代訪問)Collection集合中的元素,並安全的從Collection 中除去適當的元素,也稱為迭代器(Collection 介面的iterator()方法返回一個 Iterator) 

     Iterator中刪除操作對底層Collection也有影響,迭代器是故障快速修復(fail-fast)的。這意味著,當另一個執行緒修改底層集合的時候,如果您正在用 Iterator 遍歷集合,那麼,Iterator就會丟擲 ConcurrentModificationException (另一種 RuntimeException異常)異常並立刻失敗 

              (1) boolean hasNext(): 

                    判斷集合裡是否存在另一個可訪問的元素 

              (2) Object next(): 

                    返回集合裡下一個元素(如果到達集合結尾則丟擲NoSuchElementException異常) 

              (3) void remove(): 

                    刪除集合裡上次訪問返回的元素(本方法必須緊跟在一個元素的訪問後執行,如果上次訪問後合已被修改,方法將丟擲IllegalStateException)

 

  2、使用foreach迴圈遍歷集合元素

               (1)格式:

                        for(元素型別 t 元素變數 x : 遍歷物件A) {

                                   // 程式塊

                        }

              (2)說明:a. foreach簡化了對陣列和集合的遍歷,如果不希望遍歷整個集合,或者在迴圈內部需要操作下標值就需要使用傳統的for迴圈

                               b. 簡化了程式設計,提高了程式碼的可讀性和安全性(不用怕陣列越界)

                               c. foreach一般結合泛型使用

 

四、兩種比較介面Comparable介面和Comparator介面 

        在集合框架中有兩種比較介面:Comparable介面和Comparator介面,像String和Integer等Java內建類實現Comparable介面以提供一定排序方式,但這樣只能實現該介面一次。對於那些沒有實現Comparable介面的類、或者自定義的類,可以通過Comparator介面來定義您自己的比較方式

 

       1. Comparable介面

            在java.lang包中,Comparable介面適用於一個類有自然順序的時候。假定物件集合是同一型別,該介面允許您把集合排序成自然順序。

            int compareTo(Object o):比較當前例項物件與物件o,如果位於物件o之前,返回負值,如果兩個物件在排序中位置相同,則返回0,如果位於物件o後面,則返回正值

 

       2. Comparator介面

           若一個類不能用於實現java.lang.Comparable,或者不喜歡預設的Comparable行為並想提供自己的排序順序(可能多種排序方式),可以去實現Comparator介面,從而定義一個比較器。

            (1) int compare(Object o1, Object o2):對兩個物件o1和o2進行比較,如果o1位於o2的前面,則返回負值,如果在排序順序中認為o1和o2是相同的,返回0,如果o1位於o2的後面,則返回正值

            (2) boolean equals(Object obj):指示物件obj是否和比較器相等

 

 

五、Map介面及其子介面

       Map用於儲存具有對映關係的資料(key-vlaue),是一個儲存鍵/值對的物件(鍵必須是唯一的,值是可以重複的)(存放具有鍵值對格式資料的容器)

  Map的key是以後用於檢索值得物件,給定一個鍵和一個值,可以儲存這個值到一個Map物件中(可以使用對應鍵進行檢索值);Map的value非常類似List:元素與元素之間可以重複,每個元素可以根據索引(key)來查詢(Map有時也稱為字典,或關聯陣列

      支援對映的介面有:Map(對映唯一關鍵字給值)、Map.Entry(內部類(介面),描述對映中的元素)和SortedMap(擴充套件Map以便關鍵字按升序保持)

   Map中包括一個Entry內部類(封裝了一個鍵值對(key-value對))

            包含三個方法:Object getKey():返回該Entry裡包含的key值

                  Object getValue():返回該Entry裡包含的value值

                  Object setValue():設定並返回該Entry裡包含的新設定的value值

 Map介面中定義如下方法:

                Set entrySet():返回Map中所有包含的key-value對組成的Set集合,每個集合元素都是Map.Entry物件(把Map理解成一個特殊的Set,只是該Set裡包含的集合元素是Entry物件,而不是普通物件)

                Set keySet():返回該Map中所有key所組成的set集合

    1. HashMap和Hashtable實現類

               HashMap和Hashtable都是Map介面的實現類,Hashtable是一個古老的Map實現(JDK1.0),Hashtable是一個執行緒安全的Map實現,但HashMap(JDK1.2)是執行緒不安全的實現,但HashMap比Hashtable的效能高些

               HashMap可以使用null作為key或value( 由於HashMap裡的可以不能重複,最多隻有一對key-value值為null,但可以有無數多項key-value對的value為null)               HashMap重寫了toString()方法方法總是返回如下格式的字串:{key1 = value1,key2 = value2..}

              HashMap底層其實是個16長度的陣列(hashMap內部的結構是陣列連結串列結構(單向連結串列

不同的key有可能算出來是相同的雜湊值,根據雜湊值計算出存放到陣列的下標(有衝突)

               key一樣(同一個物件,覆蓋)

               雜湊值一樣(key不一樣),移到後面(已建立一個Entry物件)//雜湊函式能減小衝突

實現過程:

//hashmap會呼叫預設構造方法會產生一個長度為16的Entry陣列。

                      //int hash=hash(key.hashCode());

                      // 首先呼叫key的hashCode方法得來的一個整數(雜湊碼)

             //把雜湊碼作為引數傳遞到hash(雜湊函式)中來進行運算(雜湊運算),得到一個整數(雜湊值)

            // int i=indexFor(hash,table.length);

              //把雜湊值和陣列的長度來進行計算,最終得到存放到陣列的位置(下標)

 

//通過Set容器輸出HashMap中所有鍵值對(一般用該方法)

            //當我們呼叫put(key,value)這個方法的時候,首先會把key和value封裝Entry靜態內部類中

            //把Entry再新增到陣列中,所以我們只要獲取陣列中的所有Entry物件(封裝鍵值對),接下來呼叫Entry物件中的getKey()和getValue()方法就能獲得鍵值對

            Set<Entry<String,String>> entrys=map.entrySet();//entrySet():返回此對映中所包含的鍵的 set 檢視

            for(Entry<String,String> entry:entrys){

                 System.out.println(entry.getKey()+"--"+entry.getValue());

            }

 

       2. LinkedHashMap類(HashMap的子類

            LinkedHashMap是雙向連結串列來維護key-value對的次序(內部順序),該連結串列定義了迭代順序,該迭代順序與key-value對的插入順序保持一致

                 LinkedHashMap可以避免對HashMap、Hashtable裡的key-value對進行排序(只要插入key-value對時保持順序即可),LinkedHashMap需要維護元素的插入順序(效能略低於HashMap的效能,但在迭代訪問Map裡的全部元素時將有很好的效能

 

     3. SortedMap介面和TreeMap實現類

            Map介面派生了一個SortedMap子介面,TreeMap為其實現類(底層資料結構為紅黑樹)。類似TreeSet排序,TreeMap也是基於紅黑樹對TreeMap中所有key進行排序(保證TreeMap中所有key-value對處於有序狀態(自動排序)

        (1)TreeMap兩種排序方法:

                自然排序:TreeMap的所有key必須實現Comparable介面,而且所有key應該是同一個類的物件,否則將會丟擲ClassCastExcepiton異常

                定製排序:建立TreeMap時,傳入一個Comparator(比較器)物件,該物件負責對TreeMap中所有key進行排序(不要求Map的key實現Comparable介面)

            (2) TreeMap中判斷兩個key相等的標準也是兩個key通過equals比較返回true,而通過compareTo方法返回0, 如果使用自定義的類作為TreeMap的key,應重新該類的equals方法和compareTo方法時應有一致的返回結果:即兩個key通過equals方法比較返回true時,通過compareTo方法比較應該返回0

 

    總結:Map集合與Set集合元素的儲存形式很像,如Set介面下有HashSet、LinkedHashSet、SortedSet(介面)、TreeSet、EnumSet等實現類和子介面,而Map介面下則有HashMap、LinkedHashMap、SortedMap(介面)、TreeMap、EnumMap等實現類和子介面。

 

 

六、Collections類的使用

              Collections類 (類集工具類)定義了若干用於類集和對映的演算法(靜態方法),可對集合中的元素進行相關操作,為Collection和Map介面的實現類提供服務(交換(swap)、自然排序(sort)、二分化查詢(binarySearch)、打亂順序(shuffle)、填充替換(fill)

 

七、java集合總結

       如下是集合介面的UML圖,第一部分展現的是介面部分(表示不同集合型別),第二部分展現的是抽象類(對集合介面的部分實現,可擴充套件為自定義集合類),第三個部分展現的是實現類(對介面的具體是實現)

  在很大程度上,一旦您理解了介面,您就理解了框架。雖然您總要建立介面特定的實現,但訪問實際集合的方法應該限制在介面方法的使用上;因此,允許您更改基本的資料結構而不必改變其它程式碼

    java集合框架裡面所有具體類都實現了cloneable和Seriallizable介面,所以它們都可以實現克隆和可序列化

   

 

(一)將介面的引用指向實現類的物件        

              java.util中的類ArrayList實現了介面List則生成ArrayList物件時可用:List list=new ArrayList(); 也就是說所有實現了介面List的類,都可以用List介面來宣告物件型別,然後用實體類進行例項化(表明了介面可以用來作為型別的表述.當然,生成的物件list只能呼叫介面List中提供的方法)這樣的用法可以大大提高程式設計的靈活性。

            ArrayList<String> nList = new ArrayList<String>(); // 採用介面List引用物件,將介面的引用指向實現類的物件

        nList.add("chenghao");// 通過泛型限定了容器中物件的型別

           List<String> nList = new ArrayList<String>();//兩個字:多型。好處:便於程式的二次開發與維護

(二)使用迭代器來進行統一的遍歷

        1.Iterable介面

            (1) 使用該介面允許物件成為foreach語句的目標,即該集合物件允許迭代

            (2) 類集介面Collection是Iterable的子介面。所以所有類集物件可以迭代訪問,而對映Map不行

            (3) Iterator<T> Iterator(返回一組T型別的元素上進行迭代的迭代器)

        迭代器是實現了Iterator和ListIterator介面的類的物件,可以通過遍歷類集,訪問操作其中的每個元素

        System.out.println("使用迭代器來進行統一的遍歷:");

        Iterator<String> it = nList.iterator();// 返回迭代器介面的一個實現類物件

        while (it.hasNext()) {

            String name = it.next();// 取出,返回物件

            System.out.println(name);

        }

        System.out.println("使用增強的for迴圈遍歷");

        for (String name : nList) {

            System.out.println(name);

        }

    }

Collection容器

1、首先我們要了解為什麼JAVA中要有容器?
  我們知道陣列的長度一旦指定,程式在執行過程中就不能改變,正是因為陣列有這樣的缺陷,所以才出現就(collection)容器,容器的大小可以任意改變,容器的大小就是根據你實際放入了多少的資料而相應的變大。
2、容器中包括Set  和List,那麼他們有什麼區別呢?
  Set是無序唯一的,底層是用Map實現的;List是有序不唯一的,底層是陣列,所以可以用索引來得到值
  注意:在list中刪除資料時,當刪除的是裡面的整數資料型別時要知道使用包裝型別進行刪除,我們要知道JAVA會自動裝箱和拆箱  但是在Set就不需要使用包裝型別來刪除,因為Set中沒有索引
3、List又分為Arrylist和LinkedList,他們之間又有什麼區別呢?各適用於什麼情況呢?
  ArrayList(陣列)的記憶體地址連續,這個容器中的資料是經常用來查詢的;LinkedList(連結串列)記憶體地址不連續,這個容器中的資料經常用來更新
4、Iterator(容器的迭代器)
  所有實現了Collection介面的類都有一個iterator方法,這個方法會得到一個實現了Iterator的類的物件;List雖然有索引,但是也可以使用JAVA5.0以後出來的增強for迴圈,其實就相當於.Net中的foreach(),但是因為不能方便的操作索引,只用於簡單的遍歷,如果增強的for迴圈迭代的是容器的話內部預設的也是使用的Iterator迭代器實現的。但是也必須要使用迭代器來實現,因為這是唯一縣城安全的方法
5、Collections類
  該類提供了一系列的方法來對List進行操作,比如說我們自己寫的類要進行比較大小或者是排序,那麼和它相關的一切規則需要我們自己來定義,比如比較物件是否相等或者是判斷大小的規則,如果是要實現比較大小的類一定要實現Comparable介面然後重寫public int compareTo(Object o)方法,為了更美觀的輸出到控制檯上也建議重寫public String toString()方法。
6、JAVA5.0之後出現的泛型
   概念:指定當前的容器中只能放置什麼樣的型別,並且泛型中沒有父類的引用指向子類的物件
7.容器中為什麼會出現Map?
  因為Set是無序的,唯一的,hashSet沒有索引,不方便通過索引來對容器進行操作,所以出現了Map,所以Map就是可以建立索引,而且這個索引還是自己定義的。Map是以Key-value(鍵-值)對的形式來儲存資料的,新增資料是使用Map.put( index,value);index是自定義的型別,可以是自己規定的;獲取資料是使用Map.get(index) 其實Map就相當於List只是Map是添加了索引的功能

8.

集合的遍歷

       Java8中增加了lambda表示式來遍歷集合,我們這裡採用的是傳統的Iterator和foreach迴圈來遍歷,在遍歷過程中,是不能修改集合元素的,只能通過迭代器本身的方法去修改,否則會引發

ConcurrentModificationException異常,這樣可以避免共享資源引發的潛在問題