Java Collection 學習


定義:Java 作為面向對象語言,對象的操作必比然是重中之重。要操作一個對象容易,如果需要存儲多個對象,則需要一個容器,存儲多個對象可以使用數組,但是數組的長度是不可變的。所以有了集合的概念。Collection 集合,就是為了方便操作處理對象而誕生的。

本文基於 JDK 1.8 版本

Collection :來源與 Java.util 包,先看看 Collection 的全家福類圖

image

Collection 可以主要分為 set、List 、Queue 三種類型。這里 Map 是不屬於 Collection 的,Map 是一個獨立的數據結構。但是 Collention 又和 Map 的實現上又互相依賴。先說說 Collection 。

Collection 是一個的接口,是高度抽象出來的集合,包含了集合的基本操作和屬性

image

紅色框是Collection的基本方法(removeif 是1.8 出現的方法),藍色框是 JDK 8后添加的新方法。

一、Collection 基本方法

Collection基本方法:

1、添加方法
 boolean add(Object obj)	  : 添加一個對象
 boolean addAll(Collection c) : 添加一個集合的對象
2、刪除方法
 void clear() 移除所有對象
 boolean remove(Object) 移除一個對象
 boolean removeAll(Collection c) 移除一個集合的對象,只要有一個對象移除了,就返回true
3、判斷方法
 boolean contains(Object o) 判斷集合是否包含該對象
 boolean containsAll(Collection c) 判斷集合中是否包含指定的集合對象,只有包含所有的對象,才返回 true。
 boolean isEmpty() 判斷集合是否為空。
4、獲取方法
 Iterator<E> iterator() 迭代器
5、長度功能
 int size() 對象個數
6.交集功能
 boolean retainAll(Collection c) 移除此 Collection 中未包含在指定Collection 中的所有對象,簡單說就是,集合 1 和集合 2 進行對比,最終結果保存在集合 1 ,返回值表示的是 A是否發生變化。
 
Java 8 新方法:
 boolean removeif(Predicate filter) 按照一定規則過濾集合中的對象。Predicate 用於判斷對象是否符合某個條件,例:
 public static void main(String[] args) {
        List<String> list  = new ArrayList<>();
        list.add("123");
        list.add("12");
        list.add("1");

        list.removeIf(s -> s.equals("123"));
        list.forEach(s -> System.out.println(s));
    }

二、迭代器(Iterator)

在說迭代器之前先說說 Collection 繼承的 Iterable 這個接口

image

解釋一下這個 Iterable 是啥

如果一個集合對象要表明自己支持迭代,可以使用foreach語句的特權,就必須實現Iterable接口,表明這個集合對象是可迭代的!然而實現Iterable接口,就必需為foreach語句提供一個迭代器來進行 foreach 操作。

也就是 迭代器(Iterator),所以 Iterable 接口要有 Iterator() 這個方法返回一個實現了 Iterator 迭代器接口的對象。

那為什么要用這個接口而不直接實現 Iterator 接口呢?我們帶着疑問去看看!

另外提一下 spliterator 方法,返回一個 spliterator 接口。叫做可分割迭代器(splitable iterator),Spliterator就是為了並行遍歷元素而設計的一個迭代器,jdk1.8中的集合框架中的數據結構都默認實現了spliterator。這里只做一個簡單的介紹。

帶着疑問首先來看看 List 接口的 源代碼

image

可以看到 List 接口也有 Iterator 方法,下面我們看看 List 集合的實現類ArrayList

image

看到這里,可以解釋為什么 Collection 不直接實現 Iterator 接口了:

List 集合族 與 Set 集合族 ,都是實現了 Iterable 接口 ,但都不是直接實現 Iterator 接口,為什么要這樣做?

因為在 Iterator 接口的核心方法 next()或者 hasNext ()都是依賴於迭代器當前的迭代的位置。

如果 Collection 實現了 Iterator 接口,肯定會導致集合對象中包含當前迭代位置的數據(指針)。

當集合在不同方法間被傳遞的時候,由於當前迭代的位置是不可以預置。那么 next 方法的結果會變成不可預知。

這樣看使用 Iterable 接口就不會有這樣問題,每一次調用都是返回一個新的迭代器。迭代器之間是互不干擾的。

看上圖 ArrayList 的 Iterator()方法就很直觀了。


         public static void main(String[] args) {
      	    List<String> list  = new ArrayList<>();
            list.add("123");
            list.add("12");
            list.add("1");
            Iterator<String> it = list.iterator();
            while (it.hasNext()){
                System.out.println(it.next());
            }
        }

當我們使用迭代器時, 就是調用 list 實現的具體的 iterator 方法,每次使用迭代器的都是一個新的迭代器。

三、List 集合

List 接口的特點:有序集合,可以精確控制列表中每個元素的位置插入。 用戶可以通過整數索引訪問元素,並搜索列表中的元素。簡單來說就是 順序存儲,順序取出。可以重復。

List 還對 Iterator 作了實現 , ListIterator  接口。

image

ListIterator 接口比 Iterator 要多了幾個方法。

hasPrevious() 和 previous() 方法都可以實現逆向遍歷。

add()和 set()方法可以向List 中添加和修改對象。

List 集合的常用子類

ArrayList

ArrayList 是基於數組的, ArrayList 是無序的,它按照添加的先后順序排列。如果要對 ArrayList 進行排序,可以調用它的 sort()方法。並提供一個 Comparator 比較器。

ArrayList 是線程不安全的。

LinkedList

LinkedList 是基於鏈表的,它是一個雙向鏈表,每個節點維護了一個 prev 和 next 指針。同時這個鏈表維護了 first 和 last指針,分別指向第一個元素和最后一個元素。

它也是一個無序列表,也是按照插入的先后順序排序。

LInkedList 對與快速訪問元素不如 ArrayList 快,因為 ArrayList 訪問元素是隨機的。

LinkedList 也是線程不安全的。

Vector

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

由 Vector 創建的 Iterator ,雖然和 ArrayList 創建的 Iterator 是同一個接口,但是由於其同步的特性,當Vector 創建一個 Iterator 並使用時,另一個線程改變了 Vector 的狀態,比如說添加或者刪除了一些元素, 這時再調用 Iterator的方法則會拋出異常。

Stack 類繼承與 Vector 類,是一個堆棧,Stack 提供的5個額外的方法 使 vector 可以當做堆棧使用。

四、Set 集合

image

Set 集合的特點

無序,不可重復。

Set 集合中常用的子類

HashSet

底層數據結構是哈希表(一個元素為鏈表的數組)

HashSet 是基於 HashMap 實現的,有點像是對 HashMap 做了封裝,而且只是用了 HashMap 的 key 來實現其特性。

HashSet 不允許重復,如果出現重復就覆蓋,允許為空。

HashSet 是線程不安全的。

TreeSet

底層數據結構是紅黑樹 (一個自平衡的二叉樹)

TreeSet 是一個有序的集合,它的作用是提供有序的Set集合。

TreeSet的性能比HashSet差但是我們在需要排序的時候可以用TreeSet因為他是自然排序也就是升序

LinkedHashSet

底層數據結構是由哈希表和鏈表組成。

LinkedHashSet 是不重復的,按插入的順序排序。

LinkedHashSet 是線程不安全的。

五、Map 集合

為什么 Map 不繼承 Collection?

首先 Map 提供的是鍵值對映射,而 Collection 是集合接口,提供的是一組數據。如果 Map 繼承了 Collection 接口,那么所有 Map 的實現類到底是使用鍵值對還是使用 Collection 來存放數據呢?所以既然是兩種數據結構,那也就沒有必要去繼承 Collection接口了,同時還不違反接口隔離原則。假如有實現類需要使用的 Collection 接口,也不該是 Map 去繼承 Collection 接口。

六、總結

了解了以上的這些集合后,實際工作功能該如何選擇呢?

如果涉及到堆棧,隊列等操作,應該考慮使用 List ,對於需要快速插入,刪除元素,應該使用 LinkedList 。需要快速隨機訪問元素,則使用 ArrayList。

如果程序在單線程環境中,或者訪問僅在一個線程中進行,考慮非同步的類,其效率較高,如果多個線程則考慮 **同步 **的類。

要注意對哈希表的操作。作為 key 的對象要正確復寫 equals 和 hashCode 方法

感謝您的觀看,如果發現錯誤歡迎指出,謝謝!


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM