Java集合體系總結 Set、List、Map、Queue

1、java集合類基本概念java

       有時咱們須要集中存放多個數據,通常狀況下,數組就是一個很好的選擇,前提是咱們事先已經明確知道咱們將要保存的對象的數量。一旦在數組初始化時指定了這個數組長度。這樣數組長度就不可變了,若是咱們想要保存一個能夠動態增加的數據,java集合類就是一個很好的設計方案。算法

        集合類主要負責保存其餘數據,因此集合類通常也被成爲容器類。因此的集合類都位於java.util包下。數據庫

1) Collection

一組服從某種規則的元素
   1.1) List必須保持元素特定的順序
   1.2) Set不能有重複元素
   1.3) Queue保持一個隊列(先進先出)的順序
2) Map

一組成對的"鍵值對"對象

Collection  和Map的區別在於容器中每一個位置保存元素的個數編程

(1)Collection 每一個位置只能保存一個元素
(2)Map 保存的是「鍵值對」,就像一個小型數據庫。咱們能夠經過鍵找到對應的值

2、Java集合類架構層次關係數組

1.Iterface Iterable安全

迭代器接口,這是Collection類的父接口。實現這個Iterable接口的對象容許使用foreach進行遍歷,也就是說,全部的Collection集合對象都具備「foreach可遍歷性」。這個Iterable接口只有一個方法:iterator()。他返回一個表明當前集合對象的泛型<T>迭代器,用於以後的遍歷操做。數據結構

1.1 Collection 架構

Collection 是最基本的集合接口,一個Collection表明一組Object的集合,這些Object被稱做Collection的元素。Collection是一個接口,用以提供規範定義,不能被實例化使用框架

    1)Set函數

    Set集合相似於一個桶,放進Set集合裏的多個對象之間沒有明顯的順序。Set繼承自Collection接口,不能包含有重複元素。

    Set判斷兩個對象相同不是使用」==「運算符,而是根據equals方法。也就是說,咱們在加入一個新元素時,若是這個新元素對象和Set中已有對你好進行注意equals比較都返回false,則Ser就會接受這個新元素對象,不然拒絕。

    由於Set的這個制約,在使用Set集合時,應該注意兩點:1是Set集合裏的元素的實現類實現一個有效的equals(Object)方法   2對Set的構造函數,傳入的Collection參數不能包含重複的元素

        1.1)HashSet

        HastSet是Set接口的典型實現,HashSet使用HASH算法來存儲集合中的元素,所以具備良好的存取和查找性能。當向HashSet集合中存入一個元素時,HashSet會調用該對象的hashCode()方法來獲得該對象的hashCode值,而後根據該HashCode值決定該對象在HashSet的存儲位置。

            1.1.1)LinkedHashSet

            LinkedHashSet集合也是根據元素的hashCode值來決定元素的存儲位置,但和HashSet不一樣是,它同時使用鏈表維護元素的次序,這樣使得元素看起來是以插入的順序保存。

            當遍歷LinkedHashSet集合裏的元素是,LinkedHashSet將會按元素的添加順序來訪問集合裏的元素。

            LinkedHashSet須要維護元素的插入順序,所以性能略低於HashSet的性能,但在迭代訪問Set所有元素時,將會有很好的性能。

        1.2)SortedSet

        此接口主要用於排序操做,即實現此接口的子類都屬於排序的子類

            1.2.1)TreeSet

            TreeSet是Sorted接口的實現類,TreeSet能夠確保集合元素屬於排序狀態

        1.3)EnumSet

        EnumSet是一個專門爲美劇類設計的集合類,EnumSet中全部元素都必須是指定悲劇類型的的枚舉值,該枚舉類型在建立Enumset時顯示或隱式的指定。EnumSet的集合元素也是有序的。

    2)List

    List集合表明一個元素有序,可重複的集合,集合中每一個元素都有其對應的順序索引。List集合容許加入重複元素,由於他能夠經過索引來訪問指位置的集合元素,list集合默認按元素的添加順序設置元素的索引

        2.1)ArrayList

        ArrayList是基於數組實現的List類,他封裝了一個動態的增加的,容許再分配的Object[]數組。

        2.2)Vector

        Vector和ArrayList在用法上幾乎徹底相同,但因爲Vector是一個古老的集合,因此Vector提供一些方法名很長的方法,以後將Vector改成實現List接口,統一納入集合框架體系銅

            2.2.1)Stack

            Stack是Vector提供的一個子類,用於模擬棧這種數據結構

        2.3)LinkedList

        implement List<E>,Deque<E>。實現List接口,能對他進行隊列操做,便可以根據索引來隨機訪問集合中元素。同時他還實現Deque接口,即能將LinkedList當作雙端隊列使用。天然也能夠被當作「棧來使用」。

    1.2Map

    Map用於保存具備「映射關係」數據,所以Map集合裏保存着兩組值,一組值用於保存Map裏的key,另一組值用於保存Map裏的value。key和value均可以是任何引用類型的數據。Map的key不容許重複,即同一個Map對象的任何兩個Key經過equals方法比較結果老是返回false;

    Map的這些實現類和子接口中key集的存儲形式和Set集合徹底相同(即key不能重複)

    Map的這些實現類和子接口中value集的存儲形式和List很是相似(即value能夠重複,根據索引來查找)

        1)HashMap

        和HashSet不能保證元素的順序同樣,HashMap也不能保證key-value對的順序。而且相似於HashSet判斷兩個key是否相等的標準也是:兩個key經過equals()方法比較返回true。

        同時兩個key的hashCode值也必須相等。

            1.1)LinkedHashMap

            LinkedHashMap也使用雙向鏈表來維護key-value對的順序,與key-value對的插入順序一致(注意和TreeMap對全部的key-value進行排序進行區份)

        2)HashTable

            2.1)properties

        3)sortedMap

        正如Ser接口派生出SortedSet子接口,SortedSet接口有一個TreeSet實現類同樣,Map接口也派生出一個SortedMap實現類

            3.1)TreeMap

            TreeMap就是一個紅黑樹數據結構,每個key-value對即做爲紅黑樹一個節點。TreeMap存儲key-value對(節點)時,須要根據key對及誒單進行排序。TreeMap能夠包含保證全部的key-value對都處於有序狀態。一樣,TreeMap也有兩種排序方式:天然排序,定製排序

    3.Java集合類的Demo

    1.Set

    HashSet

import java.util.*

//類A的equals()方法老是返回true,但沒有重寫其hashCode()方法。不能保證當前對象是HashSet的惟一對象

class A
{
  public bollean equals(Object obj)
  {
   return true;

  }
}
//類B的hashCode()方法老是返回true,但沒有重寫其equals()方法。不能保證當前對象是HashSet的惟一對象
class B
{
  public bollean hashCode(Object obj)
  {
   return 1;

  }
}
//類C的hashCode()方法老是返回2,且有重寫其equals()方法
class C
{
    public int hashCode()
    {
        return 2;
    }
    public boolean equals(Object obj)
    {
        return true;
    }
}

 
public class HashSetTest
{
  public static void main(String[] args)
  {
        HashSet books=new HashSet();
       
         //分別向books集合中添加兩個A對象,兩個B對象,兩個C對象

        books.add(new A());
        books.add(new A());

        books.add(new B());
        books.add(new B());

        books.add(new C());
        books.add(new C());
        System.out.println(books);
   
  }
}

結果

[B@1, B@1, C@2, A@3bc257, A@785d65]

能夠看出,若是兩個對象經過equals()方法比較返回true,但這兩個對象的hashCode方法返回不一樣的hashCode值時,這將致使HashSet會把這兩個對象保存在Hash表的不一樣位置,從而使對象能夠添加成功,這就與Set集合的規則有些出入了。因此,咱們要明確的是:equals()決定是否能夠加入HashSet,而hashCode()決定存放的位置,他們二者必須同時知足才能容許一個新元素加入HashSet。

可是要注意的是:若是兩個對象的hashCode相同,可是他們的equals返回值不一樣,HashSet會在這個位置用鏈式結構來保存多個對象。而HashSet訪問集合元素時也是根據元素的HashCode的值來快速定位的,這種鏈式結構會致使性能降低。

因此若是須要把某個類的對象保存到HashSet集合中,咱們在重寫這個類的equasl()方法和hashCode()方法時,應該儘可能保證兩個對象經過equals()方法畢節哦返回true時,他們hashCode()方法返回值也相等。

    LinkedHashSet

    

import java.util.*;
public class LinkedHashSetTest
{
  public static void main(String[] args)
  {
    LinkedHashSet books=new LinkedHashSet();
    books.add('Java1');
    books.add('Java2');  
    System.out.println(books);
    //刪除 Java1
    books.remove("Java1");
    //從新添加 Java1
    books.add("Java1");
    System.out.println(books);
  }
}

    輸出

[Java1, Java2]
[Java1, Java2]

元素順序老是與添加順序一致,同時要明白的是,LinkedHashSetTest是HashSet的子類,由於它不容許集合元素重複

TreeSet

import java.util.*;

public class Test
{
    public static void main(String[] args)
    {
        TreeSet nums = new TreeSet();
        //向TreeSet中添加四個Integer對象
        nums.add(5);
        nums.add(2);
        nums.add(10);
        nums.add(-9);

        //輸出集合元素,看到集合元素已經處於排序狀態
        System.out.println(nums);
        [-9, 2, 5, 10]
        //輸出集合裏的第一個元素
        System.out.println(nums.first());
        -9
        //輸出集合裏的最後一個元素
        System.out.println(nums.last());
        10
        //返回小於4的子集,不包含4
        System.out.println(nums.headSet(4));
        [-9, 2]
        //返回大於5的子集,若是Set中包含5,子集中還包含5
        System.out.println(nums.tailSet(5));
        [5, 10]
        //返回大於等於-3,小於4的子集。
        System.out.println(nums.subSet(-3 , 4));
        [2]
    }
}

與HashSet集合採用hash算法來決定元素的存儲位置不一樣,TreeSet採用紅黑樹的數據結構來存儲集合元素。TreeSet支持兩種排序方式:天然排序,定製排序

    1.天然排序

    TreeSet 會調用集合元素的compareTo(Object obj)方法來比較元素之間的過小關係,而後將集合元素按升序排序,即天然排序,若是試圖把一個對象添加到TreeSet時,則該對象的類必須實現Comparable接口,不然程序會拋出異常。

    當把一個對象加入TreeSet集合中時,TreeSet會調用該對象的compareTo(Object obj)方法與容器中的其餘對象比較大小,而後根據紅黑樹結構找到他的存儲位置。若是兩個對象經過compareTo(Object obj)方法比較相等,新對象將沒法添加到TreeSet集合中(牢記Set不容許重複的概念)。

    注意:當須要把一個對象放入TreeSet中,重寫改對象對應類的equals()方法是,應該保證該方法時,應該保證該方法與compareTo(Object obj)方法有一致的結果,即若是有兩個對象經過equals()方法比較返回true時,這兩個對象經過compareTo(Object obj)方法比較結果應該也爲0(即相等)

    對與Set來講,它定義了equals()爲惟一性判斷的標準,而對於到了具體的實現,HashSet、TreeSet來講,它們又會有本身特有的惟一性判斷標準,只有同時知足了才能斷定爲惟一性

    2.定製排序

    TreeSet的天然排序是根據集合元素的大小,TreeSet將它們以升序排序。若是咱們須要實現定製排序,則能夠經過Comparator接口。該接口裏包含一個int compare(to1,to2)方法,該方法用戶比較大小。

import java.util.*;

class M
{
    int age;
    public M(int age)
    {
        this.age = age;
    }
    public String toString()
    {
        return "M[age:" + age + "]";
    }
}

public class  Test
{
    public static void main(String[] args)
    {
        TreeSet ts = new TreeSet(new Comparator()
        {
            //根據M對象的age屬性來決定大小
            public int compare(Object o1, Object o2)
            {
                M m1 = (M)o1;
                M m2 = (M)o2;
                return m1.age > m2.age ? -1
                        : m1.age < m2.age ? 1 : 0;
            }
        });
        ts.add(new M(5));
        ts.add(new M(-3));
        ts.add(new M(9));
        System.out.println(ts);
    }
}

EnumSet

import java.util.*;

enum Season
{
    SPRING,SUMMER,FALL,WINTER
}
public class EnumSetTest
{
    public static void main(String[] args) 
    {
        //建立一個EnumSet集合,集合元素就是Season枚舉類的所有枚舉值
        EnumSet es1 = EnumSet.allOf(Season.class);
        //輸出[SPRING,SUMMER,FALL,WINTER]
        System.out.println(es1);

        //建立一個EnumSet空集合,指定其集合元素是Season類的枚舉值。
        EnumSet es2 = EnumSet.noneOf(Season.class); 
        //輸出[]
        System.out.println(es2); 
        //手動添加兩個元素
        es2.add(Season.WINTER);
        es2.add(Season.SPRING);
        //輸出[SPRING,WINTER]
        System.out.println(es2);

        //以指定枚舉值建立EnumSet集合
        EnumSet es3 = EnumSet.of(Season.SUMMER , Season.WINTER); 
        //輸出[SUMMER,WINTER]
        System.out.println(es3);

        EnumSet es4 = EnumSet.range(Season.SUMMER , Season.WINTER); 
        //輸出[SUMMER,FALL,WINTER]
        System.out.println(es4);

        //新建立的EnumSet集合的元素和es4集合的元素有相同類型,
        //es5的集合元素 + es4集合元素 = Season枚舉類的所有枚舉值
        EnumSet es5 = EnumSet.complementOf(es4); 
        //輸出[SPRING]
        System.out.println(es5);
    }
}

輸出

[SPRING, SUMMER, FALL, WINTER]
[]
[SPRING, WINTER]
[SUMMER, WINTER]
[SUMMER, FALL, WINTER]
[SPRING]

以上是Set集合類的Demo,下面講講如何選擇這些集合類呢?

    (1)HashSet的性能老是比TreeSet好(貼別是最經常使用的添加、查詢元素等操做),由於TreeSet須要額外的紅黑樹算法來維護集合元素的次序。只有當須要一個保持排序的Set時,才應該使用TreeSet,不然都應該使用HashSet

    (2)對於普通的插入,刪除操做,LinkedHashSet比HashSet略慢一線,這是因爲維護鏈表所帶來的開銷形成的。不過,由於有了連接的存在,遍歷LinkedHashSet會更快

    (3)EnumSet是全部Set實現類中性能最好的,但它只能保存一個枚舉類的枚舉值做爲集合元素。

    (4)HashSet,TreeSet,EnumSet都是「線程不安全」的。

 2.List

    ArrayList

    若是一開始就知道ArrayList集合須要保存多少元素,則能夠在建立他們時就指定大小,這樣能夠減小從新分配的次數,提供性能,ArrayList還提供了以下方法來從新分配Object[]數組。

1) ensureCapacity(int minCapacity): 將ArrayList集合的Object[]數組長度增長minCapacity
2) trimToSize(): 調整ArrayList集合的Object[]數組長度爲當前元素的個數。
程序能夠經過此方法來減小ArrayList集合對象佔用的內存空間

    

import java.util.*;

public class Test {
    public static void main(String[] args) {
        List books = new ArrayList();
        //向books集合中添加三個元素
        books.add(new String("輕量級Java EE企業應用實戰"));
        books.add(new String("瘋狂Java講義"));
        books.add(new String("瘋狂Android講義"));
        System.out.println(books);

        //將新字符串對象插入在第二個位置
        books.add(1, new String("瘋狂Ajax講義"));
        for (int i = 0; i < books.size(); i++) {
            System.out.println(books.get(i));
        }

        //刪除第三個元素
        books.remove(2);
        System.out.println(books);

        //判斷指定元素在List集合中位置:輸出1,代表位於第二位
        System.out.println(books.indexOf(new String("瘋狂Ajax講義")));  //①
        //將第二個元素替換成新的字符串對象
        books.set(1, new String("LittleHann"));
        System.out.println(books);

        //將books集合的第二個元素(包括)
        //到第三個元素(不包括)截取成子集合
        System.out.println(books.subList(1, 2));
    }
}

輸出

[輕量級Java EE企業應用實戰, 瘋狂Java講義, 瘋狂Android講義]
輕量級Java EE企業應用實戰
瘋狂Ajax講義
瘋狂Java講義
瘋狂Android講義
[輕量級Java EE企業應用實戰, 瘋狂Ajax講義, 瘋狂Android講義]
1
[輕量級Java EE企業應用實戰, LittleHann, 瘋狂Android講義]
[LittleHann]

Stack

注意Stack的後進先出的特色

import java.util.*;

public class Test
{
    public static void main(String[] args)
    {
        Stack v = new Stack();
        //依次將三個元素push入"棧"
        v.push("瘋狂Java講義");
        v.push("輕量級Java EE企業應用實戰");
        v.push("瘋狂Android講義");

        //輸出:[瘋狂Java講義, 輕量級Java EE企業應用實戰 , 瘋狂Android講義]
        System.out.println(v);

        //訪問第一個元素,但並不將其pop出"棧",輸出:瘋狂Android講義
        System.out.println(v.peek());

        //依然輸出:[瘋狂Java講義, 輕量級Java EE企業應用實戰 , 瘋狂Android講義]
        System.out.println(v);

        //pop出第一個元素,輸出:瘋狂Android講義
        System.out.println(v.pop());

        //輸出:[瘋狂Java講義, 輕量級Java EE企業應用實戰]
        System.out.println(v);
    }
}

輸出

[瘋狂Java講義, 輕量級Java EE企業應用實戰, 瘋狂Android講義]
瘋狂Android講義
[瘋狂Java講義, 輕量級Java EE企業應用實戰, 瘋狂Android講義]
瘋狂Android講義
[瘋狂Java講義, 輕量級Java EE企業應用實戰]

LinkedList

import java.util.*;

public class Test
{
    public static void main(String[] args)
    {
        LinkedList books = new LinkedList();

        //將字符串元素加入隊列的尾部(雙端隊列)
        books.offer("瘋狂Java講義");

        //將一個字符串元素加入棧的頂部(雙端隊列)
        books.push("輕量級Java EE企業應用實戰");

        //將字符串元素添加到隊列的頭(至關於棧的頂部)
        books.offerFirst("瘋狂Android講義");

        for (int i = 0; i < books.size() ; i++ )
        {
            System.out.println(books.get(i));
        }

        //訪問、並不刪除棧頂的元素
        System.out.println(books.peekFirst());
        //訪問、並不刪除隊列的最後一個元素
        System.out.println(books.peekLast());
        //將棧頂的元素彈出"棧"
        System.out.println(books.pop());
        //下面輸出將看到隊列中第一個元素被刪除
        System.out.println(books);
        //訪問、並刪除隊列的最後一個元素
        System.out.println(books.pollLast());
        //下面輸出將看到隊列中只剩下中間一個元素:
        //輕量級Java EE企業應用實戰
        System.out.println(books);
    }
}

輸出

瘋狂Android講義
輕量級Java EE企業應用實戰
瘋狂Java講義
瘋狂Android講義
瘋狂Java講義
瘋狂Android講義
[輕量級Java EE企業應用實戰, 瘋狂Java講義]
瘋狂Java講義
[輕量級Java EE企業應用實戰]

Queue

import java.util.*;

public class PriorityQueueTest
{
    public static void main(String[] args) 
    {
        PriorityQueue pq = new PriorityQueue();
        //下面代碼依次向pq中加入四個元素
        pq.offer(6);
        pq.offer(-3);
        pq.offer(9);
        pq.offer(0);

        //輸出pq隊列,並非按元素的加入順序排列,
        //而是按元素的大小順序排列,輸出[-3, 0, 9, 6]
        System.out.println(pq);
        //訪問隊列第一個元素,其實就是隊列中最小的元素:-3
        System.out.println(pq.poll());
    }
}

PriorityQueue不容許插入null元素,它還須要對隊列元素進行排序,PriorityQueue的元素有兩種排序方式

 

    

        1) 天然排序: 採用天然順序的PriorityQueue集合中的元素對象都必須實現了Comparable接口,並且應該是同一個類的多個實例,不然可能致使ClassCastException異常

         2) 定製排序 建立PriorityQueue隊列時,傳入一個Comparator對象,該對象負責對隊列中的全部元素進行排序 關於天然排序、定製排序的原理和以前說的TreeSet相似

        ArrayDeque

import java.util.*;

public class Test
{
    public static void main(String[] args)
    {
        ArrayDeque stack = new ArrayDeque();
        //依次將三個元素push入"棧"
        stack.push("瘋狂Java講義");
        stack.push("輕量級Java EE企業應用實戰");
        stack.push("瘋狂Android講義");

        //輸出:[瘋狂Java講義, 輕量級Java EE企業應用實戰 , 瘋狂Android講義]
        System.out.println(stack);

        //訪問第一個元素,但並不將其pop出"棧",輸出:瘋狂Android講義
        System.out.println(stack.peek());

        //依然輸出:[瘋狂Java講義, 輕量級Java EE企業應用實戰 , 瘋狂Android講義]
        System.out.println(stack);

        //pop出第一個元素,輸出:瘋狂Android講義
        System.out.println(stack.pop());

        //輸出:[瘋狂Java講義, 輕量級Java EE企業應用實戰]
        System.out.println(stack);
    }
}
[瘋狂Android講義, 輕量級Java EE企業應用實戰, 瘋狂Java講義]
瘋狂Android講義
[瘋狂Android講義, 輕量級Java EE企業應用實戰, 瘋狂Java講義]
瘋狂Android講義
[輕量級Java EE企業應用實戰, 瘋狂Java講義]

以上就是List集合類的編程應用場景。咱們來梳理一下思路

    java提供的List就是一個「線性表接口」,ArrayList(基於數組的線性表),LinkedList(基於鏈的線性表)是線性表的兩種典型實現

   Queue表明了隊列,Deque表明了雙端隊列(便可以做爲隊列使用,也能夠做爲棧使用)

    由於數組以一塊連續內存來保存全部的數組元素,因此數組在隨機訪問時性能最好。

    內部以鏈表做爲底層實現的集合在執行插入,刪除操做時有很好的的性能

 

遍歷

咱們以前說過,Collection接口繼承了Iterable接口,也就是說,咱們以上學習到的全部的Collection集合類都具備"可遍歷性"

Iterable接口也是java集合框架的成員,它隱藏了各類Collection實現類的底層細節,嚮應用程序提供了遍歷Collection集合元素的統一編程接口:

1) boolean hasNext(): 是否還有下一個未遍歷過的元素
2) Object next(): 返回集合裏的下一個元素
3) void remove(): 刪除集合裏上一次next方法返回的元素

iteration

import java.util.*;

public class Test
{
    public static void main(String[] args)
    {
        //建立一個集合
        Collection books=new HashSet();
        books.add("1");
        books.add("2");
        books.add("3");
        //獲取books集合對應的迭代器
        Iterator it=books.iterator();
        while(it.hasNext())
        {
            String book=(String)it.next();
            System.out.println(book);
            if (book.equals("2"))
            {
                //從集合中刪除上一次next方法返回的元素
                it.remove();
            }
            //對book變量賦值,不會改變集合元素自己
            book = "測試字符串";
        }
        System.out.println(books);

    }
}

輸出

3
2
1
[3, 1]

從代碼能夠看出,iterator必須依附於Collection對象,如有一個iterator對象,必然有一個與之關聯的Collection對象。

除了可使用iterator接口迭代訪問Collection集合裏的元素以外,使用java5提供的foreach循環迭代訪問集合元素更加便捷

foreach 實現遍歷

import java.util.*;

public class Test
{
    public static void main(String[] args)
    {
        //建立一個集合
        Collection books = new HashSet();
        books.add(new String("1"));
        books.add(new String("2"));
        books.add(new String("3"));

        for (Object obj : books)
        {
            //此處的book變量也不是集合元素自己
            String book = (String)obj;
            System.out.println(book);
            if (book.equals("2"))
            {
                //下面代碼會引起ConcurrentModificationException異常
                //books.remove(book);
            }
        }
        System.out.println(books);
    }
}

輸出

3
2
1
[3, 2, 1]

Map

HashMap,HashTable

import java.util.*;

class A
{
    int count;
    public A(int count)
    {
        this.count = count;
    }
    //根據count的值來判斷兩個對象是否相等。
    public boolean equals(Object obj)
    {
        if (obj == this)
            return true;
        if (obj!=null &&
                obj.getClass()==A.class)
        {
            A a = (A)obj;
            return this.count == a.count;
        }
        return false;
    }
    //根據count來計算hashCode值。
    public int hashCode()
    {
        return this.count;
    }
}
class B
{
    //重寫equals()方法,B對象與任何對象經過equals()方法比較都相等
    public boolean equals(Object obj)
    {
        return true;
    }
}
public class Test
{
    public static void main(String[] args)
    {
        Hashtable ht = new Hashtable();
        ht.put(new A(60000) , "瘋狂Java講義");
        ht.put(new A(87563) , "輕量級Java EE企業應用實戰");
        ht.put(new A(1232) , new B());
        System.out.println(ht);

        //只要兩個對象經過equals比較返回true,
        //Hashtable就認爲它們是相等的value。
        //因爲Hashtable中有一個B對象,
        //它與任何對象經過equals比較都相等,因此下面輸出true。
        System.out.println(ht.containsValue("測試字符串"));  //①

        //只要兩個A對象的count相等,它們經過equals比較返回true,且hashCode相等
        //Hashtable即認爲它們是相同的key,因此下面輸出true。
        System.out.println(ht.containsKey(new A(87563)));   //②

        //下面語句能夠刪除最後一個key-value對
        ht.remove(new A(1232));    //③

        //經過返回Hashtable的全部key組成的Set集合,
        //從而遍歷Hashtable每一個key-value對
        for (Object key : ht.keySet())
        {
            System.out.print(key + "---->");
            System.out.print(ht.get(key) + "\n");
        }
    }
}

輸出

{A@ea60=瘋狂Java講義, A@1560b=輕量級Java EE企業應用實戰, A@4d0=B@547c9586}
true
true
A@ea60---->瘋狂Java講義
A@1560b---->輕量級Java EE企業應用實戰

      當使用自定義類做爲HashMap,Hashtable的key時,若是重寫該類的equals(Object obj)和hashCode()方法,則應該保證兩個方法的判斷標準一致-當兩個key經過equals()方法比較返回true時,兩個key的hashCode()的返回值也應該相同。

LinkedHashMap

import java.util.*;

public class Test
{
    public static void main(String[] args)
    {
        LinkedHashMap scores = new LinkedHashMap();
        scores.put("語文" , 80);
        scores.put("英文" , 82);
        scores.put("數學" , 76);
        //遍歷scores裏的全部的key-value對
        for (Object key : scores.keySet())
        {
            System.out.println(key + "------>" + scores.get(key));
        }
    }
}

輸出

語文------>80
英文------>82
數學------>76

properties

import java.util.*;
import java.io.*;

public class Test
{
    public static void main(String[] args) throws Exception
    {
        Properties props = new Properties();
        //向Properties中增長屬性
        props.setProperty("username" , "yeeku");
        props.setProperty("password" , "123456");

        //將Properties中的key-value對保存到a.ini文件中
        props.store(new FileOutputStream("a.ini"), "comment line");   //①

        //新建一個Properties對象
        Properties props2 = new Properties();
        //向Properties中增長屬性
        props2.setProperty("gender" , "male");

        //將a.ini文件中的key-value對追加到props2中
        props2.load(new FileInputStream("a.ini") );    //②
        System.out.println(props2);
    }
}

輸出

{password=123456, gender=male, username=yeeku}

TreeMap

import java.util.*;

class R implements Comparable
{
    int count;
    public R(int count)
    {
        this.count = count;
    }
    public String toString()
    {
        return "R[count:" + count + "]";
    }
    //根據count來判斷兩個對象是否相等。
    public boolean equals(Object obj)
    {
        if (this == obj)
            return true;
        if (obj!=null
            && obj.getClass()==R.class)
        {
            R r = (R)obj;
            return r.count == this.count;
        }
        return false;
    }
    //根據count屬性值來判斷兩個對象的大小。
    public int compareTo(Object obj)
    {
        R r = (R)obj;
        return count > r.count ? 1 :
            count < r.count ? -1 : 0;
    }
}
public class TreeMapTest
{
    public static void main(String[] args) 
    {
        TreeMap tm = new TreeMap();
        tm.put(new R(3) , "輕量級Java EE企業應用實戰");
        tm.put(new R(-5) , "瘋狂Java講義");
        tm.put(new R(9) , "瘋狂Android講義");

        System.out.println(tm);

        //返回該TreeMap的第一個Entry對象
        System.out.println(tm.firstEntry());

        //返回該TreeMap的最後一個key值
        System.out.println(tm.lastKey());

        //返回該TreeMap的比new R(2)大的最小key值。
        System.out.println(tm.higherKey(new R(2)));

        //返回該TreeMap的比new R(2)小的最大的key-value對。
        System.out.println(tm.lowerEntry(new R(2)));

        //返回該TreeMap的子TreeMap
        System.out.println(tm.subMap(new R(-1) , new R(4)));
    }
}

輸出

{R[count:-5]=瘋狂Java講義, R[count:3]=輕量級Java EE企業應用實戰, R[count:9]=瘋狂Android講義}
R[count:-5]=瘋狂Java講義
R[count:9]
R[count:3]
R[count:-5]=瘋狂Java講義
{R[count:3]=輕量級Java EE企業應用實戰}

從代碼中能夠看出,相似於TreeSet中判斷兩個元素是否相等的標準,TreeMap中判斷兩個key相等的標準是

1) 兩個key經過compareTo()方法返回0
2) equals()放回true

EnumMap

import java.util.*;

enum Season
{
    SPRING,SUMMER,FALL,WINTER
}
public class  Test
{
    public static void main(String[] args)
    {
        //建立一個EnumMap對象,該EnumMap的全部key
        //必須是Season枚舉類的枚舉值
        EnumMap enumMap = new EnumMap(Season.class);
        enumMap.put(Season.SUMMER , "夏日炎炎");
        enumMap.put(Season.SPRING , "春暖花開");
        System.out.println(enumMap);
    }
}

輸出

{SPRING=春暖花開, SUMMER=夏日炎炎}

與建立普通Map有所區別的是,建立EnumMap是必須指定一個枚舉類,從而將該EnumMap和指定枚舉類關聯起來

以上就是Map集合類的編程小demo。咱們來梳理一下思路

(1)HashMap和Hashtable的效率大體相同,由於它們的實現機制幾乎徹底同樣。但HashMap一般比Hashtable要快一點,由於Hashtable須要二外的線程同步控制

(2)TreeMap一般比HashMap,Hashtable要慢(尤爲是在插入,刪除key-value對要慢),由於TreeMap底層採用的

相關文章
相關標籤/搜索