Java Collection 學(xué)習(xí)
定義:Java 作為面向?qū)ο笳Z言茸俭,對象的操作必比然是重中之重粘都。要操作一個對象容易不跟,如果需要存儲多個對象柒巫,則需要一個容器励堡,存儲多個對象可以使用數(shù)組,但是數(shù)組的長度是不可變的堡掏。所以有了集合的概念应结。Collection 集合,就是為了方便操作處理對象而誕生的泉唁。
Collection :來源與 Java.util 包鹅龄,先看看 Collection 的全家福類圖
Collection 可以主要分為 set、List 亭畜、Queue 三種類型扮休。這里 Map 是不屬于 Collection 的,Map 是一個獨(dú)立的數(shù)據(jù)結(jié)構(gòu)拴鸵。但是 Collention 又和 Map 的實(shí)現(xiàn)上又戶型依賴玷坠。先說說 Collection 。
Collection 是一個的接口劲藐,是高度抽象出來的集合八堡,包含了集合的基本操作和屬性
紅色框是Collection的基本方法(removeif 是1.8 出現(xiàn)的方法),藍(lán)色框是 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() 對象個數(shù)
6.交集功能
boolean retainAll(Collection c) 移除此 Collection 中未包含在指定Collection 中的所有對象形庭,簡單說就是铅辞,集合 1 和集合 2 進(jìn)行對比,最終結(jié)果保存在集合 1 萨醒,返回值表示的是 A是否發(fā)生變化斟珊。
Java 8 新方法:
boolean removeif(Predicate filter) 按照一定規(guī)則過濾集合中的對象。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 這個接口
解釋一下這個 Iterable 是啥
如果一個集合對象要表明自己支持迭代,可以使用foreach語句的特權(quán)晓褪,就必須實(shí)現(xiàn)Iterable接口堵漱,表明這個集合對象是可迭代的!然而實(shí)現(xiàn)Iterable接口涣仿,就必需為foreach語句提供一個迭代器來進(jìn)行 foreach 操作勤庐。
也就是 迭代器(Iterator),所以 Iterable 接口要有 Iterator() 這個方法返回一個實(shí)現(xiàn)了 Iterator 迭代器接口的對象好港。
那為什么要用這個接口而不直接實(shí)現(xiàn) Iterator 接口呢埃元?我們帶著疑問去看看!
另外提一下 spliterator 方法媚狰,返回一個 spliterator 接口。叫做可分割迭代器(splitable iterator)阔拳,Spliterator就是為了并行遍歷元素而設(shè)計的一個迭代器崭孤,jdk1.8中的集合框架中的數(shù)據(jù)結(jié)構(gòu)都默認(rèn)實(shí)現(xiàn)了spliterator。這里只做一個簡單的介紹糊肠。
帶著疑問首先來看看 List 接口的 源代碼
可以看到 List 接口也有 Iterator 方法辨宠,下面我們看看 List 集合的實(shí)現(xiàn)類ArrayList
看到這里,可以解釋為什么 Collection 不直接實(shí)現(xiàn) Iterator 接口了:
List 集合族 與 Set 集合族 货裹,都是實(shí)現(xiàn)了 Iterable 接口 嗤形,但都不是直接實(shí)現(xiàn) Iterator 接口,為什么要這樣做弧圆?
因?yàn)樵?Iterator 接口的核心方法 next()或者 hasNext ()都是依賴于迭代器當(dāng)前的迭代的位置赋兵。
如果 Collection 實(shí)現(xiàn)了 Iterator 接口,肯定會導(dǎo)致集合對象中包含當(dāng)前迭代位置的數(shù)據(jù)(指針)搔预。
當(dāng)集合在不同方法間被傳遞的時候霹期,由于當(dāng)前迭代的位置是不可以預(yù)置。那么 next 方法的結(jié)果會變成不可預(yù)知拯田。
這樣看使用 Iterable 接口就不會有這樣問題历造,每一次調(diào)用都是返回一個新的迭代器。迭代器之間是互不干擾的。
看上圖 ArrayList 的 Iterator()方法就很直觀了吭产。
public static void main(String[]args) {
List<String>list=newArrayList<>();
list.add("123");
list.add("12");
list.add("1");
//獲取迭代器
Iterator<String>it=list.iterator();
while(it.hasNext()){
System.out.println(it.next());
}
}
當(dāng)我們使用迭代器時, 就是調(diào)用 list 實(shí)現(xiàn)的具體的 iterator 方法侣监,每次使用迭代器的都是一個新的迭代器。
三臣淤、List 集合
List 接口的特點(diǎn):有序集合橄霉,可以精確控制列表中每個元素的位置插入。 用戶可以通過整數(shù)索引訪問元素荒典,并搜索列表中的元素酪劫。簡單來說就是 順序存儲,順序取出寺董「苍悖可以重復(fù)。
List 還對 Iterator 作了實(shí)現(xiàn) 遮咖, ListIterator 接口滩字。
ListIterator 接口比 Iterator 要多了幾個方法。
hasPrevious() 和 previous() 方法都可以實(shí)現(xiàn)逆向遍歷御吞。
add()和 set()方法可以向List 中添加和修改對象麦箍。
List 集合的常用子類
ArrayList
ArrayList 是基于數(shù)組的, ArrayList 是無序的陶珠,它按照添加的先后順序排列挟裂。如果要對 ArrayList 進(jìn)行排序,可以調(diào)用它的 sort()方法揍诽。并提供一個 Comparator 比較器诀蓉。
ArrayList 是線程不安全的。
LinkedList
LinkedList 是基于鏈表的暑脆,它是一個雙向鏈表渠啤,每個節(jié)點(diǎn)維護(hù)了一個 prev 和 next 指針。同時這個鏈表維護(hù)了 first 和 last指針添吗,分別指向第一個元素和最后一個元素沥曹。
它也是一個無序列表,也是按照插入的先后順序排序碟联。
LInkedList 對與快速訪問元素不如 ArrayList 快妓美,因?yàn)?ArrayList 訪問元素是隨機(jī)的。
LinkedList 也是線程不安全的鲤孵。
Vector
Vector 和 ArrayList 非常類似部脚,但Vector 是同步的。
由 Vector 創(chuàng)建的 Iterator 裤纹,雖然和 ArrayList 創(chuàng)建的 Iterator 是同一個接口委刘,但是由于其同步的特性丧没,當(dāng)Vector 創(chuàng)建一個 Iterator 并使用時,另一個線程改變了 Vector 的狀態(tài)锡移,比如說添加或者刪除了一些元素呕童, 這時再調(diào)用 Iterator的方法則會拋出異常。
Stack 類繼承與 Vector 類淆珊,是一個堆棧夺饲,Stack 提供的5個額外的方法 使 vector 可以當(dāng)做堆棧使用。
四施符、Set 集合
Set 集合的特點(diǎn)
無序往声,不可重復(fù)。
Set 集合中常用的子類
HashSet
底層數(shù)據(jù)結(jié)構(gòu)是哈希表(一個元素為鏈表的數(shù)組)
HashSet 是基于 HashMap 實(shí)現(xiàn)的戳吝,有點(diǎn)像是對 HashMap 做了封裝浩销,而且只是用了 HashMap 的 key 來實(shí)現(xiàn)其特性。
HashSet 不允許重復(fù)听哭,如果出現(xiàn)重復(fù)就覆蓋慢洋,允許為空。
HashSet 是線程不安全的陆盘。
TreeSet
底層數(shù)據(jù)結(jié)構(gòu)是紅黑樹 (一個自平衡的二叉樹)
TreeSet 是一個有序的集合普筹,它的作用是提供有序的Set集合。
TreeSet的性能比HashSet差但是我們在需要排序的時候可以用TreeSet因?yàn)樗亲匀慌判蛞簿褪巧?/p>
LinkedHashSet
底層數(shù)據(jù)結(jié)構(gòu)是由哈希表和鏈表組成隘马。
LinkedHashSet 是不重復(fù)的太防,按插入的順序排序。
LinkedHashSet 是線程不安全的酸员。
五杏头、Map 集合
為什么 Map 不繼承 Collection?
首先 Map 提供的是鍵值對映射沸呐,而 Collection 是集合接口,提供的是一組數(shù)據(jù)呢燥。如果 Map 繼承了 Collection 接口崭添,那么所有 Map 的實(shí)現(xiàn)類到底是使用鍵值對還是使用 Collection 來存放數(shù)據(jù)呢?所以既然是兩種數(shù)據(jù)結(jié)構(gòu)叛氨,那也就沒有必要去繼承 Collection接口了呼渣,同時還不違反接口隔離原則。假如有實(shí)現(xiàn)類需要使用的 Collection 接口寞埠,也不該是 Map 去繼承 Collection 接口屁置。
六、總結(jié)
了解了以上的這些集合后仁连,實(shí)際工作功能該如何選擇呢蓝角?
如果涉及到堆棧阱穗,隊列等操作,應(yīng)該考慮使用 List 使鹅,對于需要快速插入揪阶,刪除元素,應(yīng)該使用 LinkedList 患朱。需要快速隨機(jī)訪問元素鲁僚,則使用 ArrayList。
如果程序在單線程環(huán)境中裁厅,或者訪問僅在一個線程中進(jìn)行冰沙,考慮非同步的類,其效率較高执虹,如果多個線程則考慮 **同步 **的類拓挥。
要注意對哈希表的操作。作為 key 的對象要正確復(fù)寫 equals 和 hashCode 方法
感謝您的觀看声畏,如果發(fā)現(xiàn)錯誤歡迎指出撞叽,謝謝!