java集合類總結

集合類說明及區別

(注:引用小李專欄部分內容,代碼來自星星傳奇,感謝)

1、結構:
Collection
├List
│├LinkedList
│├ArrayList
│└Vector
│ └Stack
└Set
Map
├Hashtable
├HashMap
└WeakHashMap

2、簡介

Set、List和Map可以看做集合的三大類。

     List集合是有序集合,集合中的元素可以重複,訪問集合中的元素可以根據元素的索引來訪問。

     Set集合是無序集合,集合中的元素不可以重複,訪問集合中的元素只能根據元素本身來訪問(也是不能集合裏元素不允許重複的原因)。

     Map集合中保存Key-value對形式的元素,訪問時只能根據每項元素的key來訪問其value。


Collection接口

  由Collection接口派生的兩個接口是List和Set。下面是Collection的添加元素、刪除元素、返回集合中元素的個數以及清空集合元素的方法。

public class TestCollection
{
    public static void main(String[] args) 
    {
        Collection c = new ArrayList();
        //添加元素
        c.add("孫悟空");
        //雖然集合裏不能放基本類型的值,但Java支持自動裝箱
        c.add(6);
        System.out.println("c集合的元素個數爲:" + c.size());   
     //刪除指定元素
        c.remove(6);     
    System.out.println("c集合的元素個數爲:" + c.size());
        //判斷是否包含指定字符串
        System.out.println("c集合的是否包含孫悟空字符串:" + c.contains("孫悟空"));
        c.add("輕量級J2EE企業應用實戰");
        System.out.println("c集合的元素:" + c);        
    Collection books = new HashSet();
        books.add("輕量級J2EE企業應用實戰");
        books.add("Struts2權威指南");
        System.out.println("c集合是否完全包含books集合?" + c.containsAll(books));
        //用c集合減去books集合裏的元素
        c.removeAll(books);
        System.out.println("c集合的元素:" + c);
        //刪除c集合裏所有元素
        c.clear();
        System.out.println("c集合的元素:" + c);
        //books集合裏只剩下c集合裏也同時包含的元素
        books.retainAll(c);
        System.out.println("books集合的元素:" + books);
    }
}


List接口
  實現List接口的常用類有LinkedList,ArrayList,Vector和Stack

LinkedList類
  LinkedList實現了List接口,允許null元素。

      

“這些操作使LinkedList可被用作堆棧(stack),隊列(queue)或雙向隊列(deque)”
   LinkedList沒有同步方法。如果多個線程同時訪問一個List,則必須自己實現訪問同步。一種解決方法是在創建List時構造一個同步的List:
   List list = Collections.synchronizedList(new LinkedList(...));

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

       void ensureCapacity(int minCapacity): 將ArrayList對象容量增加minCapacity
  和LinkedList一樣,ArrayList也是非同步的(unsynchronized)

Vector類
  Vector非常類似ArrayList,但是
Vector是同步的

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

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

Set接口
  Set是一種不包含重複的元素的Collection,即任意的兩個元素e1和e2都有e1.equals(e2)=false,Set最多有一個null元素。

Map接口
  請注意,Map沒有繼承Collection接口,Map提供key到value的映射。一個Map中不能包含相同的key,每個key只能映射一個 value。Map接口提供3種集合的視圖,Map的內容可以被當作一組key集合,一組value集合,或者一組key-value映射。

Hashtable類
  Hashtable繼承Map接口,實現一個key-value映射的哈希表。任何非空(non-null)的對象都可作爲key或者value。
  添加數據使用put(key, value),取出數據使用get(key),這兩個基本操作的時間開銷爲常數。
      使用Hashtable的簡單示例如下,將1,2,3放到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);
  由於作爲key的對象將通過計算其散列函數來確定與之對應的value的位置,因此任何作爲key的對象都必須實現hashCode和equals方 法。hashCode和equals方法繼承自根類Object,如果你用自定義的類當作key的話,要相當小心,按照散列函數的定義,如果兩個對象相 同,即obj1.equals(obj2)=true,則它們的hashCode必須相同,但如果兩個對象不同,則它們的hashCode不一定不同,如 果兩個不同對象的hashCode相同,這種現象稱爲衝突,衝突會導致操作哈希表的時間開銷增大,所以儘量定義好的hashCode()方法,能加快哈希 表的操作。
  如果相同的對象有不同的hashCode,對哈希表的操作會出現意想不到的結果(期待的get方法返回null),要避免這種問題,只需要牢記一條:要同時複寫equals方法和hashCode方法,而不要只寫其中一個。
  Hashtable是同步的。

HashMap類
  HashMap和Hashtable類似,不同之處在於HashMap是非同步的,並且允許null,即null value和null key。,但是將HashMap視爲Collection時(values()方法可返回Collection),其迭代子操作時間開銷和HashMap 的容量成比例。因此,如果迭代操作的性能相當重要的話,不要將HashMap的初始化容量設得過高,或者load factor過低。

兩種遍歷集合的方法Iterator接口和foreach循環

  1、Iterator接口

 Iterator也是Java集合框架的成員,主要用於遍歷(即迭代訪問)Collection集合中的元素,也稱爲迭代器。

提供的三種方法:

boolean hasNext():返回集合裏的下一個元素。

Object next():返回集合裏下一個元素。

void remove();刪除集合裏上一次next方法返回的元素。

public class TestIterator 
{ 
    public static void main(String[] args) 
    { 
        //創建一個集合 
        Collection books = new HashSet(); 
        books.add("輕量級J2EE企業應用實戰"); 
        books.add("Struts2權威指南"); 
        books.add("基於J2EE的Ajax寶典"); 

        //獲取books集合對應的迭代器 
        Iterator it = books.iterator(); 
        while(it.hasNext()) 
        { 
       //未使用泛型,需要強制轉換
            String book = (String)it.next(); 
            System.out.println(book); 

            if (book.equals("Struts2權威指南")) 
            { 
                it.remove();
            //使用Iterator迭代過程中,不可修改集合元素,下面代碼引發異常
            //books.remove(book); 
            } 
           //對book變量賦值,不會改變集合元素本身 
             book = "測試字符串"; 
        } 
        System.out.println(books); 
    } 
}

  2、使用foreach循環遍歷集合元素。

格式:for(元素類型 t  元素變量 x : 遍歷對象A) {

                     // 程序塊

}

說明:

(1)foreach簡化了對數組和集合的遍歷,如果不希望遍歷整個集合,或者在循環內部需要操作下標值就需要使用傳統的for循環。

(2)簡化了編程,提高了代碼的可讀性和安全性(不用怕數組越界)。

(3)foreach一般結合泛型使用

public class TestArray {
    public static void main(String args[]) {
        TestArray test = new TestArray();
        test.test1();
        test.listToArray();
        test.testArray3();
    }

    /**
     * foreach語句輸出一維數組
     */
    public void test1() {
        // 定義並初始化一個數組
        int arr[] = { 2, 3, 1 };
        System.out.println("----1----排序前的一維數組");

        for (int x : arr) {
            System.out.println(x); // 逐個輸出數組元素的值
        }

        // 對數組排序
        Arrays.sort(arr);

        // 利用java新特性for each循環輸出數組
        System.out.println("----1----排序後的一維數組");

        for (int x : arr) {
            System.out.println(x); // 逐個輸出數組元素的值
        }
    }

    /**
     * 集合轉換爲一維數組
     */
    public void listToArray() {
        // 創建List並添加元素
        List<String> list = new ArrayList<String>();
        list.add("1");
        list.add("3");
        list.add("4");
        // 利用froeach語句輸出集合元素
        System.out.println("----2----froeach語句輸出集合元素");
        for (String x : list) {
            System.out.println(x);
        }

        // 將ArrayList轉換爲數組
        Object s[] = list.toArray();

        // 利用froeach語句輸出集合元素
        System.out.println("----2----froeach語句輸出集合轉換而來的數組元素");

        for (Object x : s) {
            System.out.println(x.toString()); // 逐個輸出數組元素的值
        }
    }

    /**
     * foreach輸出二維數組測試
     */
    public void testArray2() {
        int arr2[][] = { { 4, 3 }, { 1, 2 } };

        System.out.println("----3----foreach輸出二維數組測試");

        for (int x[] : arr2) {
            for (int e : x) {
                System.out.println(e); // 逐個輸出數組元素的值
            }
        }
    }

    /**
     * foreach輸出三維數組
     */
    public void testArray3() {
        int arr[][][] = { { { 1, 2 }, { 3, 4 } }, { { 5, 6 }, { 7, 8 } } };

        System.out.println("----4----foreach輸出三維數組測試");

        for (int[][] a2 : arr) {
            for (int[] a1 : a2) {
                for (int x : a1) {
                    System.out.println(x);
                }
            }
        }
    }
}

總結
  如果涉及到堆棧,隊列等操作,應該考慮用List,對於需要快速插入,刪除元素,應該使用LinkedList,如果需要快速隨機訪問元素,應該使用ArrayList。
  如果程序在單線程環境中,或者訪問僅僅在一個線程中進行,考慮非同步的類,其效率較高,如果多個線程可能同時操作一個類,應該使用同步的類。
  要特別注意對哈希表的操作,作爲key的對象要正確複寫equals和hashCode方法。
  儘量返回接口而非實際的類型,如返回List而非ArrayList,這樣如果以後需要將ArrayList換成LinkedList時,客戶端代碼不用改變。這就是針對抽象編程。

同步性
Vector是同步的。這個類中的一些方法保證了Vector中的對象是線程安全的。而ArrayList則是異步的,因此ArrayList中的對象並 不是線程安全的。因爲同步的要求會影響執行的效率,所以如果你不需要線程安全的集合那麼使用ArrayList是一個很好的選擇,這樣可以避免由於同步帶 來的不必要的性能開銷。

相互區別

Vector和ArrayList

1,vector是線程同步的,所以它也是線程安全的,而arraylist是線程異步的,是不安全的。如果不考慮到線程的安全因素,一般用

arraylist效率比較高。
2,如果集合中的元素的數目大於目前集合數組的長度時,vector增長率爲目前數組長度的100%,而arraylist增長率爲目前數組長度

的50%.如過在集合中使用數據量比較大的數據,用vector有一定的優勢。
3,如果查找一個指定位置的數據,vector和arraylist使用的時間是相同的,都是0(1),這個時候使用vector和arraylist都可以。而

如果移動一個指定位置的數據花費的時間爲0(n-i)n爲總長度,這個時候就應該考慮到使用linklist,因爲它移動一個指定位置的數據

所花費的時間爲0(1),而查詢一個指定位置的數據時花費的時間爲0(i)。

ArrayList 和Vector是採用數組方式存儲數據,此數組元素數大於實際存儲的數據以便增加和插入元素,都允許直接序號索引元素,但是插入數據要設計到數組元素移動 等內存操作,所以索引數據快插入數據慢,Vector由於使用了synchronized方法(線程安全)所以性能上比ArrayList要 差,LinkedList使用雙向鏈表實現存儲,按序號索引數據需要進行向前或向後遍歷,但是插入數據時只需要記錄本項的前後項即可,所以插入數度較快!


arraylist和linkedlist

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


hashtable與hashmap

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

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

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

發佈了22 篇原創文章 · 獲贊 6 · 訪問量 5萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章