Java集合詳解Collection、Map



        Java Collections FrameworkJava提供的對集合進行定義,操作,和管理的統一的架構。這個集合框架主要由接口、抽象類、實現類構成。

Java的集合有兩大接口:CollectionMap

 

Collection接口
  

API解釋:Collection是層次結構中的根接口Collection 表示一組對象,這些對象也稱爲 collection 的元素。一些 collection 允許有重複的元素,而另一些則不允許。一些 collection 是有序的,而另一些則是無序的。JDK 不提供此接口的任何直接 實現:它提供更具體的子接口(如 Set List,這兩個是最常用的子接口)實現。此接口通常用來傳遞 collection,並在需要最大普遍性的地方操作這些 collection

 

       Collection是最基本的集合接口,一個Collection代表一組Object,即Collection的元素(Elements)就是一個對象。

 

       java集合只能保存引用類型的數據,是對象的引用

 

Java SDK不提供直接繼承自Collection的類,只提供了子接口,如SetListJava SDK提供的類都是繼承自Collection的“子接口”如ListSet

 

       所有通用的 Collection 實現類(通常通過它的一個子接口間接實現 Collection)應該提供兩個“標準”構造方法:一個是 void(無參數)構造方法,用於創建空 collection;另一個是帶有 Collection 類型單參數的構造方法,用於創建一個具有與其參數相同元素新的 collection。實際上,後者允許用戶複製任何 collection,以生成所需實現類型的一個等效 collection。儘管無法強制執行此約定(因爲接口不能包含構造方法),但是 Java 平臺庫中所有通用的 Collection 實現都遵從它。

 

 

 

Collection常見方法:

add(E e);  addAll(Collection c); 

contains(Obj o) ---- 返回是否包含指定的元素(true false)

containsAll(Collection c) ----  返回是否包含c中所有元素

isEmpty();  iterator(); remove();  clear();  size(); toArray();

 

 

     

 

Java集合框架的基本接口/類層次結構:

 

[I]:接口

[C]:類

 

java.util.Collection [I]

+--java.util.List [I]

   +--java.util.ArrayList [C]

   +--java.util.LinkedList [C]

   +--java.util.Vector [C]

      +--java.util.Stack [C]

+--java.util.Set [I]

   +--java.util.HashSet [C]

   +--java.util.SortedSet [I]

      +--java.util.TreeSet [C]

 

java.util.Map [I]

+--java.util.SortedMap [I]

   +--java.util.TreeMap [C]

+--java.util.Hashtable [C]

+--java.util.HashMap [C]

+--java.util.LinkedHashMap [C]

+--java.util.WeakHashMap [C]

 

 

 

 

 

List子接口

1 可以包含重複的元素

2 是一個有序的集合,位置不可以改變,使用此接口能夠精確的控制每個元素插入的位置。

3、提供了按索引訪問的方式。用戶能夠使用索引(元素在List中的位置,類似於數組下標)來訪問List中的元素,這類似於Java的數組。 

4 、除了具有Collection接口必備的iterator()方法外,List還提供一個listIterator()方法,返回一個ListIterator接口,和標準的Iterator接口相比,ListIterator多了一些add()之類的方法,允許添加,刪除,設定元素,還能向前或向後遍歷。
  實現List接口的常用類有LinkedListArrayListVectorStack

 

 

LinkedList

 

此外LinkedList提供額外的getremoveinsert方法在 LinkedList的首部或尾部。這些操作使LinkedList可被用作堆棧(stack),隊列(queue)或雙向隊列(deque)。
   
注意LinkedList沒有同步方法。如果多個線程同時訪問一個List,則必須自己實現訪問同步。一種解決方法是在創建List時構造一個同步的List

    List list =Collections.synchronizedList(new LinkedList(...)); 

 

 

 

ArrayList

 

List 接口的大小可變數組的實現。實現了所有可選列表操作,並允許包括null在內的所有元素。

 

每個ArrayList實例都有一個容量(Capacity),即用於存儲元素的數組的大小。這個容量可隨着不斷添加新元素而自動增加,但是增長算法 並沒有定義。當需要插入大量元素時,在插入前可以調用ensureCapacity方法來增加ArrayList的容量以提高插入效率。

 

常用方法:add()

 

ArrayList  list = new ArrayList();

List.add(“aaaaa”);

List.add(“bbbbb”);

       //因爲是有序的,可以使用for循環輸出

       for( ){

              SOP(list);

}

 

 

   利用ArrayListtoArray()返回一個對象的數組;  也可以利用Arrays.asList()方法返回一個列表

Arrays.asList()Collection.toArray()是作爲數組和集合類的一個橋

如果想從集合類中獲得一個數組可以使用toArray()方法;如果想從數組中獲得一個列表可以使用asList()方法

 

import java.util.*;

class Point {

int x, y;

Point(int x, int y) {

   this.x = x;

   this.y = y;

}

public String toString() {

   return "x=" + x +",y=" + y;

}

}

public class ArrayListToArrayTest {

public static void main(String[] args) {

   ArrayList a1 = newArrayList();

   a1.add(new Point(3, 3));

   a1.add(new Point(4, 4));

   a1.add(new Point(5, 5));

 

   for (int i = 0; i <a1.size(); i++) {

   System.out.println(a1.get(i));

   }

   System.out.println(a1);

 

   Object[] objs = a1.toArray();// 利用ArrayListtoArray()返回一個對象的數組.

   for (int i = 0; i <objs.length; i++) {

    System.out.println(objs[i]);

   }

   System.out.println(objs);//

   List l =Arrays.asList(objs);// Arrays.asList()返回一個列表.

   System.out.println(l);

 

}

}

結果:

 

x=3,y=3

x=4,y=4

x=5,y=5

[x=3,y=3, x=4,y=4, x=5,y=5]

x=3,y=3

x=4,y=4

x=5,y=5

[Ljava.lang.Object;@1fc4bec

[x=3,y=3, x=4,y=4, x=5,y=5]

 

 

LinkedList一樣,ArrayList也是非同步的(unsynchronized)。

 

 

 

Vector
  Vector非常類似ArrayList,但是Vector是同步的。由Vector創建的Iterator,雖然和 ArrayList創建的Iterator是同一接口,但是,因爲Vector是同步的,當一個Iterator被創建而且正在被使用,另一個線程改變了 Vector的狀態(例如,添加或刪除了一些元素),這時調用Iterator的方法時將拋出 ConcurrentModificationException,因此必須捕獲該異常

 

 

 

Stack
  Stack繼承自Vector,實現一個後進先出的堆棧。Stack提供5個額外的方法使得Vector得以被當作堆棧使用。基本的pushpop 方法,還有peek方法得到棧頂的元素,empty方法測試堆棧是否爲空,search方法檢測一個元素在堆棧中的位置。Stack剛創建後是空棧。

 

 

 

 

Set子接口

不可以包含重複的元素。即任意的兩個元素e1e2都有e1.equals(e2)=falseSet最多有一個null元素

 

Set是一個無序的集合,但是子接口SorttedSet是一個按照升序進行排列元素的Set

 

很明顯,Set的構造函數有一個約束條件,傳入的Collection參數不能包含重複的元素。

 

HashSet

        此類實現 Set 接口,由哈希表(實際上是一個 HashMap 實例)支持。它不保證集合的迭代順序;特別是它不保證該順序恆久不變。此類允許使用 null 元素。
    HashSet
不是同步的,需要用以下語句來進行S同步轉換:
           Set s = Collections.synchronizedSet(new HashSet(...))

 

 

SortedSet

       Set的一個子接口。TreeSet實現了SortedSet

 

 

 

SetList比較:
    Set
:檢索元素效率低下,刪除和插入效率高,插入和刪除不會引起元素位置改變。
    List
:和數組類似,List可以動態增長,查找元素效率高,插入刪除元素效率低,因爲會引起其他元素位置改變。

 

 

 


比較:

arraylistlinkedlist

1.ArrayList是實現了基於動態數組的數據結構LinkedList基於鏈表的數據結構。
2.
對於隨機訪問getsetArrayList覺得優於LinkedList,因爲LinkedList要移動指針。
3.
對於新增和刪除操作addremoveLinedList比較佔優勢,因爲ArrayList要移動數據。
   
這一點要看實際情況的。若只對單條數據插入或刪除,ArrayList的速度反而優於LinkedList。但若是批量隨機的插入刪除數據,LinkedList的速度大大優於ArrayList. 因爲ArrayList每插入一條數據,要移動插入點及之後的所有數據。

 

 

 

 ------------------------------------------------------------------------------------------------------------------------------------------------------------------------

 

 

Map接口:

       API: 將鍵映射到值的對象。一個映射不能包含重複的鍵;每個鍵最多隻能映射一個值。

Map 接口提供三種collection視圖(注意:這個collectionCollection是不同的概念,collection表示集合,Collection表示集合下的一個藉口Collection),允許以鍵集、值集合或鍵-值映射關係集的形式查看某個映射的內容。映射的順序 定義爲迭代器在映射的 collection 視圖中返回其元素的順序。某些映射實現可明確保證其順序,如 TreeMap 類;某些映射實現則不保證順序,如 HashMap 類。

 

Map沒有繼承Collection接口。也就是說MapCollection2種不同的集合。

 

Collection可以看作是(value)的集合,而Map可以看作是(keyvalue)的集合。


     Map
接口由Map的內容提供3種類型的集合視圖,一組key集合,一組value集合,或者一組key-value映射關係的集合。

 

一個Map中不能包含相同的key,每個key只能映射一個 value

 

 

 

Map可以出現在kv的映射中,vnull的情況。

       Map集合允許值對象爲null,並且沒有個數限制,所以當get()方法的返回值爲null時,可能有兩種情況,一種是在集合中沒有該鍵對象,另一種是該鍵對象沒有映射任何值對象,即值對象爲null。因此,在Map集合中不應該利用get()方法來判斷是否存在某個鍵,而應該利用containsKey()方法來判斷。

         package com;

import java.util.HashMap;

import java.util.Map;

public class te {

    public static void main(String[] args) { 

         

        Map<String,String> map = new HashMap<String,String>();

        map.put("k", null);    // 向列表中添加數據 

        /**

         * 使用get()判斷Map中是否包含某個鍵值對,會出現判斷不準確的情況

         * */

        System.out.println(map.get("kkk"));  //輸出結果 null

        System.out.println(map.get("k"));    //輸出結果 null

       

        /**

         * 正確的做法是:containsKey()方法來判斷

         * */

        map.put("cc", "ggggggggggg"); // 向列表中添加數據 

        boolean contains = map.containsKey("cc");   //返回truefalse

        if (contains) { 

            System.out.println("Map集合中包含鍵值對"); 

        } else { 

            System.out.println("Map集合中不包含鍵值對"); 

        } 

   } 

}

 

 

 

操作方法:

可以把這個接口方法分成三組操作:改變、查詢和提供可選視圖。

 

改變操作允許從映射中添加和除去鍵-值對。鍵和值都可以爲 null。但是,不能把Map 作爲一個鍵或值添加給自身。

 

Object put(Objectkey, Object value)返回值是被替換的值。

Objectremove(Object key)

void putAll(Mapmapping)

void clear()

查詢操作允許您檢查映射內容:

 

Object get(Objectkey)

booleancontainsKey(Object key)

booleancontainsValue(Object value)

int size()

boolean isEmpty()

最後一組方法允許您把鍵或值的組作爲集合來處理。

 

public SetkeySet()

public Collectionvalues()

public SetentrySet()

因爲映射中鍵的集合必須是唯一的,您用 Set 支持。因爲映射中值的集合可能不唯一,您用Collection 支持。最後一個方法返回一個實現 Map.Entry 接口的元素 Set

 

 

 

Map.Entry 接口

Map entrySet() 方法返回一個實現Map.Entry 接口的對象集合。集合中每個對象都是底層 Map 中一個特定的鍵-值對。

 

通過這個集合迭代,您可以獲得每一條目的鍵或值並對值進行更改。但是,如果底層 Map Map.Entry 接口的setValue() 方法外部被修改,此條目集就會變得無效,並導致迭代器行爲未定義。

 

 

Hashtable

 

       Hashtable 繼承自 Dictiionary

       Hashtable實現Map接口,實現一個key-value映射的哈希表。key或者value不允許爲空。

Hashtable通過initial capacityload factor兩個參數調整性能。通常缺省的load factor 0.75較好地實現了時間和空間的均衡。增大load factor可以節省空間但相應的查找時間將增大,這會影響像getput這樣的操作。
使用Hashtable的簡單示例如下,將123放到Hashtable中,他們的key分別是”one””two””three”
    Hashtable numbers = new Hashtable();
    numbers.put(“one”, new Integer(1));
    numbers.put(“two”, new Integer(2));
    numbers.put(“three”, new Integer(3));
  要取出一個數,比如2,用相應的key
    Integer n = (Integer)numbers.get(“two”);
    System.out.println(“two = ” + n);

  1. 由於作爲key的對象將通過計算其散列函數來確定與之對應的value的位置,因此任何作爲key的對象都必須實現hashCodeequals方法。hashCodeequals方法繼承自根類Object

 

  1. 如果你用自定義的類當作key的話,要相當小心,按照散列函數的定義,如果兩個對象相同,即obj1.equals(obj2)=true,則它們的hashCode必須相同,但如果兩個對象不同,則它們的hashCode不一定不同。如 果兩個不同對象的hashCode相同,這種現象稱爲衝突,衝突會導致操作哈希表的時間開銷增大,所以儘量定義好的hashCode()方法,能加快哈希 表的操作。

     

3、如果相同的對象有不同的hashCode,對哈希表的操作會出現意想不到的結果(期待的get方法返回null),要避免這種問題,只需要牢記一條:要同時複寫equals方法和hashCode方法,而不要只寫其中一個。
  Hashtable是同步的。

 

 

HashMap

      

       繼承了AbstractMap

       不是同步的Map

允許null,即nullvaluenull key

 

 

 

 

WeakHashMap
  WeakHashMap是一種改進的HashMap,它對key實行弱引用,如果一個key不再被外部所引用,那麼該key可以被GC回收。



 

 

相互比較:

 

hashtablehashmap

 

.歷史原因:Hashtable是基於陳舊的Dictionary類的,HashMapJava 1.2引進的Map接口的一個實現

.同步性:Hashtable是線程安全的,也就是說是同步的,而HashMap是線程序不安全的,不是同步的

.值:只有HashMap可以讓你將空值作爲一個表的條目的keyvalue

 

 

HashMapTreeMap

       1  HashMap通過hashcode對其內容進行快速查找,而TreeMap中所有的元素都保持着某種固定的順序,如果你需要得到一個有序的結果你就應該 使用TreeMapHashMap中元素的排列順序是不固定的)。集合框架提供兩種常規的Map實現:HashMapTreeMap (TreeMap實現SortedMap接口)

       2 Map 中插入、刪除和定位元素,HashMap 是最好的選擇。但如果您要按自然順序或自定義順序遍歷鍵,那麼TreeMap會更好。使用HashMap要求添加的鍵類明確定義了hashCode() equals()的實現。  這個TreeMap沒有調優選項,因爲該樹總處於平衡狀態。

 結過研究,二樹map一樣,但順序不一樣,導致hashCode()不一樣。  同樣做測試:
     
hashMap中,同樣的值的map,順序不同,equals時,false;
     
而在treeMap中,同樣的值的map,順序不同,equals時,true,說明,treeMapequals()時是整理了順序了的。

 

 

 

 ------------------------------------------------------------------------------------------------------------------------------------------------------------------------

 

各種情況下適合使用哪種集合:

       如果涉及到堆棧,隊列等操作,應該考慮用List,對於需要快速插入,刪除元素,應該使用LinkedList,如果需要快速隨機訪問元素,應該使用ArrayList
  如果程序在單線程環境中,或者訪問僅僅在一個線程中進行,考慮非同步的類,比如HashMap,其效率較高,如果多個線程可能同時操作一個類,應該使用同步的類。

       要特別注意對哈希表的操作,作爲key的對象要正確複寫equalshashCode方法。
  儘量返回接口而非實際的類型,如返回List而非ArrayList,這樣如果以後需要將ArrayList換成LinkedList時,客戶端代碼不用改變。這就是針對抽象編程

 

 

 ------------------------------------------------------------------------------------------------------------------------------------------------------------------------

 

如何遍歷Collection中的每一個元素?

 

1、增強for循環 for(Objo:c){syso(o)}

     2、使用iterator Iteratorit=c.iterator;

         while(it.hasNext()){Object o = it.next()}

     3、普通循環:for(Iteratorit=c.iterator();it.hasNext();){it.next() }

 

 

       注意:不論Collection的實際類型如何,一般都是實現Collection接口的子接口List或者Set,而生成的實際類型。它都支持一個iterator()的方法,該方法返回一個迭代子,使用該迭代子即可逐一訪問Collection中每一個元素。典型的用法如下:
    Iterator it =collection.iterator(); // 獲得一個迭代子
    while(it.hasNext()){
      Object obj =it.next(); // 得到下一個元素
    }

 

------------------------------------------------------------------------------------------------------------------------------------------------------------












 歸納總結:

 

接口

簡述

實現

操作特性

成員要求

Set

成員不能重複

HashSet

外部無序地遍歷成員

成員可爲任意Object子類的對象,但如果覆蓋了equals方法,同時注意修改hashCode方法。

TreeSet

外部有序地遍歷成員;附加實現了SortedSet, 支持子集等要求順序的操作

成員要求實現caparable接口,或者使用 Comparator構造TreeSet。成員一般爲同一類型。

LinkedHashSet

外部按成員的插入順序遍歷成員

成員與HashSet成員類似

List

提供基於索引的對成員的隨機訪問

ArrayList

提供快速的基於索引的成員訪問,對尾部成員的增加和刪除支持較好

成員可爲任意Object子類的對象

LinkedList

對列表中任何位置的成員的增加和刪除支持較好,但對基於索引的成員訪問支持性能較差

成員可爲任意Object子類的對象

Map

保存鍵值對成員,基於鍵找值操作,compareTocompare方法對鍵排序

HashMap

能滿足用戶對Map的通用需求

鍵成員可爲任意Object子類的對象,但如果覆蓋了equals方法,同時注意修改hashCode方法。

TreeMap

支持對鍵有序地遍歷,使用時建議先用HashMap增加和刪除成員,最後從HashMap生成TreeMap;附加實現了SortedMap接口,支持子Map等要求順序的操作

鍵成員要求實現caparable接口,或者使用Comparator構造TreeMap。鍵成員一般爲同一類型。

LinkedHashMap

保留鍵的插入順序,用equals 方法檢查鍵和值的相等性

成員可爲任意Object子類的對象,但如果覆蓋了equals方法,同時注意修改hashCode方法。

IdentityHashMap

使用== 來檢查鍵和值的相等性。

成員使用的是嚴格相等

WeakHashMap

其行爲依賴於垃圾回收線程,沒有絕對理由則少用

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章