夯實Java基礎(十九)——集合

一、前言

集合在Java中的地位想必你們都知道,不用多BB了。不管是在咱們如今的學習中仍是在從此的工做中,集合這樣一個你們族都無處不在,無處不用。在前面講到的數組也是一個小的容器,可是數組不是面向對象對象的,它存在明顯的缺陷,而集合剛好彌補了數組帶來的缺陷。集合比數組更加靈活、更加實用。並且不一樣的集合框架可用於不一樣的場景。html

咱們簡單來比較一下數組和集合區別:java

  • 一、數組能存放基本數據類型和對象,而集合類中只能存放對象。
  • 二、數組容量固定沒法動態改變,集合類容量能夠動態改變。
  • 三、數組沒法判斷其中實際存有多少元素,length只告訴了數組的容量,而集合的size()能夠確切知道元素的個數。
  • 四、集合有多種實現方式和不一樣適用場合,不像數組僅採用順序表方式。
  • 五、集合以類的形式存在,具備封裝、繼承、多態等類的特性,經過簡單的方法和屬性便可實現各類複雜操做,從而大大提升了軟件的開發效率。

爲了清晰的認識Java集合你們族,下面是整個Java集合的框架圖:算法

經過上面的圖片能夠看到集合你們族的成員以及他們之間的關係。發現這也太多了吧,不過不要太慌張。咱們如今只須要抓住它們的主幹便可,即Collection、Map和Iterator,額外的還有兩個對集合操做的工具類Collections和Arrays。其中虛框表示的是接口或抽象類,實框是類,虛箭頭是實現,實箭頭是繼承。而後把它們捋一捋給分個類就應該清楚了。數組

二、集合的分類

上面的Java集合框架圖看起來比較的雜亂,因此咱們對它們進行了分類處理,這樣更加直觀。安全

Collection接口:最基本的集合接口(單列數據)
├——-List接口:全部元素按照進入的前後順序有序存儲,可重複集合
│—————-├ ArrayList:接口實現類,用數組實現,隨機訪問,增刪慢,查詢快,沒有同步,線程不安全 
│—————-├ LinkedList:接口實現類,用雙向鏈表實現, 插入刪除快,查詢慢, 沒有同步,線程不安全 
│—————-└ Vector:接口實現類,用數組實現,它和ArrayList幾乎同樣,可是它是同步, 線程安全的(Vector幾乎已經不用了)
└———————-└ Stack:繼承自Vector類,Stack具備後進先出的特色 
└——-Set接口:不容許包含重複的值(能夠有null,可是隻有一個),無序,不可重複集合
├—————-└HashSet:使用hash表(數組)存儲元素,無序,其底層是包裝了一個HashMap去實現的,因此查詢插入速度較快
│————————└ LinkedHashSet:繼承HashSet類,它新增了一個重要特性,就是元素按照插入的順序存儲
├ —————-TreeSet:底層基於TreeMap實現的,它支持2種排序方式:天然排序(Comparable)和定製排序(Comparator)數據結構

└ ——-Queue接口:隊列,它的特色是先進先出框架

Map接口:鍵值對的集合接口,不容許含有相同的key,有則輸出一個key-value組合(雙列數據)
├———Hashtable:接口實現類,用hash表實現,不可重複key,key不能爲null,同步,效率稍低,線程安全
├———HashMap:接口實現類 ,用hash表實現,不可重複key,key能夠爲null,沒有同步,效率稍高 ,線程不安全
│—————–├ LinkedHashMap:雙向鏈表和hash表實現,按照key的插入順序存放
│——— WeakHashMap:和HashMap同樣,但它的鍵是「弱鍵」,垃圾收集器會自動的清除沒有在其餘任何地方被引用的鍵值對ide

├ ——–TreeMap:用紅黑樹算法實現,它默認按照全部的key進行排序
└———IdentifyHashMap:它是一個特殊的Map實現,它的內部判斷key是否相等用的是 ==,而HashMap則更加複雜函數

簡單完成分類以後咱們就從集合的特色和區別來進行一 一講解。工具

三、Collection接口

Collection是最基本的集合接口,它是單列數據集合。在JDK中不提供Collection接口的任何直接實現,它只提供了更具體的子接口(即繼承自Collection接口),例如List列表,Set集合,Queue隊列,而後再由具體的類來實現這些子接口。經過具體類實現接口以後它們的特徵就得以凸顯出來,有些集合中的元素是有序的,而其餘的集合中的元素則是無序的;有些集合容許重複的元素,而其餘的集合則不容許重複的元素;有些集合容許排序,而其餘的集合則不容許排序。

既然Collection接口是集合的層次結構的根接口,那麼一定有經常使用的方法,咱們來看一下:

  1. boolean add(E e):向集合中添加一個元素。集合更改則添加成功返回true,若是該集合不容許重複而且已經包含指定的元素。返回false。部分子類的add方法可能會限制添加到集合中的元素類型,或者不會將NULL添加到集合中。
  2. boolean addAll(Collection<? extends E> c):將指定集合中的全部元素添加到此集合中。在添加過程當中若是被添加的集合發生了更改,addAll方法不具備冪等性。
  3. void clear():清空掉集合中的全部元素。
  4. boolean contains(Object o):若是集合中包含指定元素那麼返回true。特別的,若是集合中也包含NULL元素的時候而且要查找的元素也是NULL的時候也返回true。
  5. boolean containsAll(Collection<?> c):若是該集合中包含指定集合中的全部元素的時候返回true。
  6. boolean isEmpty():若是集合中不包含元素返回true。
  7. Iterator<E> iterator():返回在此集合的元素上進行迭代的迭代器。關於元素返回的順序沒有任何保證,除非此集合是某個能提供保證順序的類實例。 
  8. boolean remove(Object o):刪除集合中的指定的元素。若是存在NULL,也刪除。
  9. boolean removeAll(Collection<?> c):刪除當前集合中全部等於指定集合中的元素。
  10. boolean retainAll(Collection<?> c):僅保留此集合中那些也包含在指定集合的元素。移除此集合中未包含在指定集合中的全部元素。
  11. int size():返回該集合中元素的個數。若是超過了Integer.MAX_VALUE,那麼返回Integer.MAX_VALUE。
  12. Object[] toArray():返回包含此集合中因此元素的數組。
  13. <T> T[] toArray():返回包含此集合中全部元素的數組; 返回的數組的運行時類型是指定數組的運行時類型。

四、Iterator接口

咱們從上面Collection結構中能夠看到其內部有一個iterator()方法,這個方法不是Collection中所特有的,而是重寫了父類Iterable中的。由於Collection接口繼承了java.lang.Iterable接口,而該接口中有一個iterator()方法。也就是說全部實現了Collection接口的集合類中都有iterator()方法,它用來返回實現了Iterator接口的迭代器對象。

Iterator接口的內部結構比較簡單,其內部只定義的四個方法,它們分別是:

  1. boolean hasNext():若是迭代具備更多元素,則返回true。
  2. E next():返回迭代器中游標的下一元素。
  3. default void remove():從集合中刪除此迭代器返回的最後一個元素。每次調用next後只能調用一次此方法,不能屢次調用,不然會報錯。若是在進行迭代時用調用此方法以外的其餘方式修改了該迭代器所指向的集合,那麼則迭代器的行爲是不肯定的。
  4. default void forEachRemaining(Consumer<? super E> action):對每一個剩餘元素執行給定的操做,直到全部元素都被處理或動做引起異常。若是指定了迭代的順序,則按迭代的順序執行。操做引起的異常將被轉發給調用者。

迭代器的簡單舉例:

public static void main(String[] args) {
        //hasNext()、next()測試
        Collection coll = new ArrayList();
        coll.add(123);
        coll.add(456);
        coll.add('A');
        coll.add(true);
        coll.add(new String("Collection..."));
        //建立迭代器對象
        Iterator iterator = coll.iterator();
        while (iterator.hasNext()) {
            System.out.println(iterator.next());
        }
        System.out.println("----------------------");

        //remove()測試。若是還未調用next()或在上次調用next()方法以後已經調用了remove()方法,
        //那麼在再次用remove()方法會報錯java.lang.IllegalStateException
        Iterator iterator1 = coll.iterator();
        while (iterator1.hasNext()) {
            //iterator1.remove();不能在next()前先調用
            Object next = iterator1.next();
            if (next.equals(456)) {
                iterator1.remove();
                //iterator1.remove();不能在next()後再次調
            }
        }
        iterator1 = coll.iterator();
        while (iterator1.hasNext()) {
            System.out.println(iterator1.next());
        }
    }
    //運行結果:
    //123
    //456
    //A
    //true
    //Collection...
    //----------------------
    //123
    //A
    //true
    //Collection...

簡易分析一下:當返回了Iterator對象以後能夠理解爲有一個指針,它指在第一個對象的上面(即123的上面,此時指針爲空),當咱們調用iterator.hasNext()的時候,判斷是否還有下一個元素,若是有則返回true。而後調用iterator.next()使指針往下移而且返回下移之後集合位置上的元素,這樣以此類推就輸出了以上結果。

五、List接口

List接口直接繼承了Collection接口,它對Collection進行了簡單的擴充,從而讓集合凸顯出它們各自的特徵。在List中全部元素的存儲都是有序的,並且是可重複存儲的。用戶能夠根據元素存儲位置的索引來操做元素。實現了List接口的集合主要有如下幾個:ArrayList、LinkedList、Vector和Stack。

注意:List集合它有一個特有的迭代器——ListIterator。Iterator的子接口ListIterator是專門給List集合提供的迭代元素的接口,它的內部對Iterator功能進行一些擴充。例如增長的方法有hasPrevious()、nextIndex()、previousIndex()等等。

既然List接口直接繼承了Collection接口,並且List是有序存儲結構,那麼List除了從Collection中繼承的方法以外,一定會本身添加一些根據索引來操做集合元素的方法,咱們來看一下:

  1. void add(int index, E element):將指定的元素插入此列表中的指定位置(可選操做)。
  2. boolean addAll(int index, Collection<? extends E> c):將指定集合中的全部元素插入到此列表中的指定位置。 
  3. E get(int index):返回此列表中指定位置的元素。 
  4. int indexOf(Object o):返回此列表中指定元素的第一次出現的索引,若是此列表不包含元素,則返回-1。 
  5. int lastIndexOf(Object o):返回此列表中指定元素的最後一次出現的索引,若是此列表不包含元素,則返回-1。 
  6. E remove(int index):刪除該列表中指定位置的元素(可選操做)。 
  7. E set(int index, E element):用指定的元素(可選操做)替換此列表中指定位置的元素。 
  8. List<E> subList(int fromIndex, int toIndex):返回從fromIndex到toIndex位置上的子集合。

5.一、ArrayList

ArrayList應該是咱們最多見的集合,同時也是List中最重要的一個。ArrayList的特色是:隨機訪問、查詢快,增刪慢,輕量級,線程不安全。它的底層是用Object數組實現的,咱們能夠把ArrayList看作是一個可改變大小的數組。隨着愈來愈多的元素被添加到ArrayList中,其容量是動態增長的(初始化容量是10,增量是原來的1.5倍  int newCapacity = oldCapacity + (oldCapacity >> 1);)。

5.二、LinkedList

LinkedList底層是經過雙向鏈表實現的,因此它不能隨機訪問,並且須要查找元素必需要從開頭或結尾(從靠近指定索引的一端)開始一個一個的找。使用雙向鏈表則讓增長、刪除元素比較的方便,但查詢變得困難。因此LinkedList的特色是:查詢慢,增刪快,線程不安全。

因爲LinkedList是雙向鏈表實現的,因此它除了有List中的基本操做方法外還額外提供了一些方法在LinkedList的首部或尾部進行操做的方法(實際上是繼承Deque中的),如addXXX()、getXXX()、removeXXX()等等。同時,LinkedList還實現了Queue接口的子接口Deque,因此他還提供了offer(), peek(), poll()、pop()、push()等方法。咱們簡單來看一下:

  1. void addFirst(E e):在該列表開頭插入指定的元素。
  2. void addLast(E e):將指定的元素追加到此列表的末尾。
  3. E element():檢索但不刪除此列表的頭(第一個元素)。
  4. E getFirst():返回此列表中的第一個元素。
  5. E getLast():返回此列表中的最後一個元素。
  6. boolean offer(E e):將指定的元素添加爲此列表的尾部(最後一個元素)。
  7. boolean offerFirst(E e):在此列表的前面插入指定的元素。
  8. boolean offerLast(E e):在該列表的末尾插入指定的元素。
  9. E poll XXX():檢索並刪除此列表的頭(第一個元素)。
  10. E peek XXX():檢索但不刪除此列表的頭(第一個元素)。
  11. E pop():今後列表表示的堆棧中彈出一個元素。
  12. void push(E e):將元素推送到由此列表表示的堆棧上。
  13. E remove XXX():從列表中刪除指定元素的第一個出現(若是存在)。

5.三、Vector

Vector和ArrayList幾乎同樣,它們都是經過Object數組來實現的。可是Vector是線程安全的,和ArrayList相比,Vector中不少方法是用synchronized關鍵字處理過來保證證數據安全,這就必然會影響其效率,因此你的程序若是不涉及到線程安全問題,那麼推薦使用ArrayList集合。其實不管如何你們都會選擇ArrayList的,由於Vector已經不多用了,幾乎面臨淘汰。

另外兩者還有一個區別就是Vector和ArrayList的擴容策略不同,Vector的擴容增量是原來容量的2倍,而ArrayList是原來的1.5倍。

5.四、Stack

Stack的名稱是堆棧。它是繼承自Vector這個類,這就意味着,Stack也是經過數組來實現的。Stack的特性是:先進後出(FILO, First In Last Out)。此外Stack中還提供5個額外的方法使得Vector得以被看成堆棧使用。咱們來看一下這五個方法:

  1. boolean empty():測試堆棧是否爲空。Stack剛建立後就是空棧。
  2. E peek():查看此堆棧頂部的對象,而不從堆棧中刪除它。
  3. E pop():出棧,刪除此堆棧頂部的對象,並將該對象做爲此函數的值返回。 
  4. E push(E item):壓棧,將元素推送到此堆棧的頂部。
  5. int search(Object o):返回一個對象在此堆棧上的基於1的位置。

六、Set接口

Set和List同樣都是繼承自Collection接口,可是Set和List的特色徹底不同。Set集合中的元素是無順序的,且沒有重複的元素。若是你試圖將多個相同的對象添加到Set中,那麼很差意思,它會立馬阻止。Set中會用equals()和hashCode()方法來判斷兩個對象是否相同,只要該方法的結果是true,Set就不會再次接收這個對象了。實現了Set接口主要有一下幾個:HashSet、LinkedHashSet、TreeSet、EnumSet。Set中沒有增長任何新的方法,用的都是繼承自中Collection中的。

6.一、HashSet

HashSet是按照哈希算法(hashCode)來存儲集合中的對象,因此它是無序的,同時也不能保證元素的排列順序。其底層是包裝了一個HashMap去實現的,因此其查詢效率很是高。並且在增長和刪除的時候因爲運用hashCode的值來比較肯定添加和刪除元素的位置,因此不存在元素的偏移,效率也很是高。所以HashSet的查詢、增長和刪除元素的效率都是很是高的。可是HashSet增刪的高效率是經過花費大量的空間換來的:由於空間越大,取餘數相同的狀況就越小。HashSet這種算法會創建許多無用的空間。使用HashSet接口時要注意,若是發生衝突,就會出現遍歷整個數組的狀況,這樣就使得效率很是的低。HashSet使用簡單舉例:

public class HashSetTest {
    public static void main(String[] args) {
        //建立HashSet的實例
        HashSet<String> hashSet = new HashSet<>();
        //添加了兩個AA元素
        hashSet.add("AA");
        hashSet.add("AA");
        hashSet.add("BB");
        //添加了兩個CC元素
        hashSet.add("CC");
        hashSet.add("CC");
        hashSet.add("DD");
        hashSet.add("EE");
        hashSet.add("FF");
        hashSet.add("GG");
        //遍歷打印結果
        for (String s : hashSet) {
            System.out.println(s+",hash值是:"+s.hashCode());
        }
    }
}
//運行結果:
//AA,hash值是:2080
//BB,hash值是:2112
//CC,hash值是:2144
//DD,hash值是:2176
//EE,hash值是:2208
//FF,hash值是:2240
//GG,hash值是:2272

6.二、LinkedHashSet

LinkedHashSet繼承自HashSet類,它不只實現了哈希算法(hashCode),還實現了鏈表的數據結構,提供了插入和刪除的功能。他有HashSet所有特性,但它新增了一個重要特性,就是元素按照插入的順序存儲。因此當遍歷LinkedHashSet集合裏的元素時,LinkedHashSet將會按元素的添加順序來訪問集合裏的元素。正是由於多加了這樣一種數據結構,因此它的效率較低,不建議使用,若是要求一個集合急要保證元素不重複,也須要記錄元素的前後添加順序,才選擇使用LinkedHashSet。LinkedHashSet使用簡單舉例:

public class LinkedHashSetTest {
    public static void main(String[] args) {
        //建立LinkedHashSet實例
        LinkedHashSet<String> linkedHashSet = new LinkedHashSet<>();
        //無序添加元素
        linkedHashSet.add("DD");
        linkedHashSet.add("BB");
        linkedHashSet.add("AA");
        linkedHashSet.add("GG");
        linkedHashSet.add("EE");
        linkedHashSet.add("FF");
        linkedHashSet.add("CC");
        //遍歷打印值
        for (String s : linkedHashSet) {
            System.out.println(s+",hash值:"+s.hashCode());
        }
        //刪除GG元素
        boolean gg = linkedHashSet.remove("GG");
        System.out.println(gg);
    }
}
//運行結果:
//DD,hash值:2176
//BB,hash值:2112
//AA,hash值:2080
//GG,hash值:2272
//EE,hash值:2208
//FF,hash值:2240
//CC,hash值:2144
//true

6.三、TreeSet

TreeSet的底層是基於TreeMap中實現的。它不只能保證元素的惟一性,還能對元素按照某種規則進行排序。它繼承了AbstractSet抽象類,實現了NavigableSet <E>,Cloneable,可序列化接口。而NavigableSet <E>又繼承了SortedSet接口,此接口主要用於排序操做,即實現此接口的子類都屬於排序的子類,有可排序的功能。TreeSet中的元素支持2種排序方式:天然排序或者定製排序,使用方式具體取決於咱們使用的構造方法(默認使用天然排序)。TreeSet使用簡單舉例:

public class TreeSetTest {
    public static void main(String[] args) {
        //建立TreeSet實例、使用Comparator定製排序
        TreeSet<Integer> treeSet = new TreeSet<>(new Comparator<Integer>() {
            //排序方式爲:降序
            @Override
            public int compare(Integer o1, Integer o2) {
                if (o1>o2){
                    return -1;
                }else if(o1<o2){
                   return 1;
                }else {
                    return 0;
                }
            }
        });
        treeSet.add(2);
        treeSet.add(2);
        treeSet.add(4);
        treeSet.add(4);
        treeSet.add(1);
        treeSet.add(1);
        treeSet.add(3);
        treeSet.add(3);
        for (Integer integer : treeSet) {
            System.out.println(integer);
        }
    }
}
//輸出結果:
//4
//3
//2
//1

6.四、EnumSet

EnumSet是專門爲枚舉類而設計的有序集合類,EnumSet中全部元素都必須是指定枚舉類型的枚舉值,在建立EnumSet時必須顯式或隱式指定它對應的枚舉類。EnumSet使用簡單舉例:

//建立枚舉類
public enum Season {
    SPRING,SUMMER,AUTUMN,WINNER;
}

class Test{
    public static void main(String[] args) {
        //EnumSet的簡單使用
        EnumSet<Season> seasons = EnumSet.allOf(Season.class);
        //遍歷
        for (Season season : seasons) {
            System.out.println(season);
        }
    }
}
//輸出結果:
//SPRING
//SUMMER
//AUTUMN
//WINNER

七、Queue接口

Queue接口與List、Set是同一級別的,都繼承了Collection接口。Queue表示的是隊列,它的特色是:先進先出(FIFO,First-in-First-Out) 。隊列主要分爲兩大類:一類是BlockingDeque阻塞隊列(Queue的子接口),它的主要實現類包括ArrayBlockQueue、PriorityBlockingQueue. LinkedBlockingQueue。另外一類是Deque雙端隊列(也是Queue的子接口),支持在頭部和尾部兩端插入和移除元素,主要實現類包括:ArrayDeque、LinkedList。

Queue接口中包含的方法有:

  1. booleab add(E e):插入指定的元素要隊列中,並返回true或者false,若是隊列數量超過了容量,則拋出IllegalStateException的異常。
  2. boolean offer(E e):插入指定的元素到隊列,並返回true或者false,若是隊列數量超過了容量,不會拋出異常,只會返回false。
  3. E remove():搜索並刪除最頂層的隊列元素,若是隊列爲空,則拋出一個Exception。
  4. E poll():搜索並刪除最頂層的隊列元素,若是隊列爲空,則返回null。
  5. E element():檢索但不刪除並返回隊列中最頂層的元素,若是該隊列爲空,則拋出一個Exception。
  6. E peek(): 檢索但不刪除並返回最頂層的元素,若是該隊列爲空,則返回null。

對於BlockingDeque阻塞隊列的詳解能夠參考這篇博客:BlockingQueue(阻塞隊列)詳解 ,寫的很是不錯。

八、Map接口

Map接口與Collection接口是徹底不一樣的。Map中保存的是具備「映射關係」的數據,便是由一系列鍵值對組成的集合,提供了key到value的映射,也就是說一個key對應一個value,其中key和value均可以是任何引用數據類型。可是Map中不能存在相同的key值,對於相同key值的Map對象會經過equals()方法來判斷key值是否相等,只要該方法的結果是true,Map就不會再次接收這個對象了,固然value值能夠相同。實現了Map接口的類主要的有如下幾個:HashMap、Hashtable、LinkedHashMap、WeakHashMap、TreeMap、IdentifyHashMap、EnumMap。其中Map集合還和Set集合有着很是緊密的聯繫,由於不少Set集合中底層就是用Map來實現的。

咱們來看一下Map鍵值對根接口中的方法:

  1. void clear():刪除該map集合中的全部鍵值對映射。
  2. boolean containsKey(Object key):檢測map中有沒有包含指定值爲key的元素,若是有則返回true,不然返回false。
  3. boolean containsValue(Object value):檢測map中有沒有包含指定值爲value的元素,若是有則返回true,不然返回false。
  4. Set<Map.Entry<K,V>> entrySet():返回map到一個Set集合中,以map集合中的Key=Value的形式返回到set中。
  5. V get(Object key):根據map集合中指定的key值來獲取相應value值。
  6. Set<K> keySet():返回map集合中全部key。
  7. V put(K key,V value):向map集合中添加key的值和value的值,當添加成功時返回null,不然返回value。
  8. void putAll(Map<? extends K,? extends V> m):把一個map集合合併到另外一個map集合裏。
  9. V remove(Object key):刪除指定值爲key的元素。
  10. int size():返回map集合中元素大小。
  11. Collection<V> values():返回map集合中全部的value值到一個Collection集合。

遍歷Map中的對象:Java中四種遍歷Map對象的方法

8.一、Hashtable

Hashtable是一個古老的Map實現類,在JDK1.0就提供了,它繼承自Dictionary類,底層基於hash表結構+數組+鏈表實現實現,內部全部方法都是同步的,即線程很安全,可是效率低。注意在Hashtable中key和value均不可爲null。

8.二、HashMap

HashMap是Map集合中使用最多的,它是Hashtable的一個輕量級版本,它是繼承了Abstractmap類,底層也是基於hash表結構+鏈表(紅黑樹,鏈表長度大於8會將鏈表轉化成紅黑樹)+數組實現的,內部全部方法是不一樣步的,即線程不安全,可是效率高。在HashtMap中key和value均都可爲null。

8.三、LinkedHashMap

LinkedHashMap基於雙向鏈表和數組實現,內部結構和HashMap相似,就是多加了一個雙向鏈表結構。根據key的插入順序進行存儲。(注意和TreeMap對全部的key-value進行排序進行區分)

8.四、WeakHashMap

WeakHashMap與HashMap的用法基本類似。區別在於,HashMap的key保留了對實際對象的"強引用",這意味着只要該HashMap對象不被銷燬,該HashMap所引用的對象就不會被垃圾回收。但WeakHashMap的key只保留了對實際對象的弱引用,這意味着若是WeakHashMap對象的key所引用的對象沒有被其餘強引用變量所引用,則這些key所引用的對象可能被垃圾回收,當垃圾回收了該key所對應的實際對象以後,WeakHashMap也可能自動刪除這些key所對應的key-value對。

8.五、TreeMap

TreeMap底層是用紅黑樹算法實現,它實現SortMap接口,因此其內部元素默認按照全部的key進行排序。固然也支持2種排序方式:天然排序或者定製排序。其中TreeMap中的key不可null,而它非線程安全的。使用能夠參考上面的TreeSet示例,使用方式差很少。

8.六、IdentifyHashMap

IdentityHashMap是一種可重複key的集合類。它和HashMap相似,因此咱們通常都是拿IdentityHashMap和HashMap來進行比較,由於它們二者判斷重複key的方式不同。IdentifyHashMap中判斷重複key相等的條件是:(k1==k2),也就是說它只比較普通值是否相等,不比較對象中的內容。而HashMap中類判斷重複key相等的條件是: (k1==null?k2==null:k1.equals(k2))==true),它不只比較普通值,並且比對象中的內容是否相等。簡單舉例:

public class MapTest {
    public static void main(String[] args) {
        //建立HashMap實例,添加Integer實例爲key
        HashMap hashMap=new HashMap();
        hashMap.put(1,"hello");
        hashMap.put(1,"hello");
        hashMap.put(new Integer(2),"hello");
        hashMap.put(new Integer(2),"hello");
        hashMap.put(new Integer(2),"hello");
        System.out.println("HashMap:"+hashMap.toString());
        //建立IdentityHashMap實例,添加Integer實例爲key
        IdentityHashMap<Object, Object> identityHashMap = new IdentityHashMap<>();
        identityHashMap.put(3,"world");
        identityHashMap.put(3,"world");
        identityHashMap.put(new Integer(4),"world");
        identityHashMap.put(new Integer(5),"world");
        identityHashMap.put(new Integer(4),"world");
        System.out.println("IdentityHashMap:"+identityHashMap.toString());
    }
}
//運行結果:
//HashMap:{1=hello, 2=hello}
//IdentityHashMap:{4=world, 4=world, 3=world, 5=world}

8.七、EnumMap

EnumMap這個類是專門爲枚舉類而設計的有鍵值對的集合類。集合中的全部鍵(key)都必須是單個同一個類型的枚舉值,建立EnumMap時必須顯式或隱式指定它對應的枚舉類。當EnumMap建立後,其內部是以數組形式保存,因此這種實現形式很是緊湊高效。EnumMap根據key的天然順序(即枚舉值在枚舉類中的定義順序)來維護來維護key-value對的次序。能夠經過keySet()、entrySet()、values()等方法來遍歷EnumMap便可看到這種順序。EnumMap不容許使用null做爲key值,但容許使用null做爲value。若是試圖使用null做爲key將拋出NullPointerException異常。若是僅僅只是查詢是否包含值爲null的key、或者僅僅只是使用刪除值爲null的key,都不會拋出異常。EnumMap的代碼示例以下:

//建立枚舉類
public enum Season {
    SPRING,SUMMER,AUTUMN,WINNER;
}

class Test{
    public static void main(String[] args) {
        //EnumMap的簡單使用
        EnumMap<Season,String> map=new EnumMap<Season, String>(Season.class);
        map.put(Season.SPRING,"春暖花開");
        map.put(Season.SUMMER,"夏日炎炎");
        map.put(Season.AUTUMN,"秋高氣爽");
        map.put(Season.WINNER,"冬暖夏涼");
        //遍歷map有不少種方式,這裏是map遍歷的一種方式,這種方式是最快的
        for (EnumMap.Entry<Season,String> entry:map.entrySet()){
            System.out.println(entry.getKey()+","+entry.getValue());
        }
    }
}
//輸出結果:
//SPRING,春暖花開
//SUMMER,夏日炎炎
//AUTUMN,秋高氣爽
//WINNER,冬暖夏涼

九、Collections工具類

Collections是集合的一個工具類或者幫助類,其中提供了一系列靜態方法,用於對集合中元素進行排序、搜索以及線程安全等各類操做。

  1. addAll(Collection<? super T> c, T... elements):將全部指定的元素添加到指定的集合。
  2. copy(List<? super T> dest, List<? extends T> src):將全部元素從一個列表複製到另外一個列表中。
  3. disjoint(Collection<?> c1, Collection<?> c2):若是兩個指定的集合沒有共同的元素,則返回 true 。
  4. fill(List<? super T> list, T obj):用指定的元素代替指定列表的全部元素。
  5. max(Collection<? extends T> coll):根據其元素的天然順序返回給定集合的最大元素。
  6. min(Collection<? extends T> coll):根據其元素的天然順序返回給定集合的最小元素。
  7. nCopies(int n, T o):返回由指定對象的 n副本組成的不可變列表。
  8. replaceAll(List<T> list, T oldVal, T newVal):將列表中一個指定值的全部出現替換爲另外一個。
  9. reverse(List<?> list):反轉指定列表中元素的順序。
  10. rotate(List<?> list, int distance):將指定列表中的元素旋轉指定的距離。
  11. shuffle(List<?> list):使用默認的隨機源隨機排列指定的列表。
  12. sort(List<T> list):對集合列表進行排序。
  13. swap(List<?> list, int i, int j):交換指定列表中指定位置的元素。

以上只是一些常見的方法,若是須要了解更多的方法能夠自行去查看Collections的API。

Relevant Link

http://www.javashuo.com/article/p-wjyklgab-n.html

http://www.javashuo.com/article/p-miqztzvv-a.html

相關文章
相關標籤/搜索