Collection集合總結
Collection介面繼承體系圖
Collection介面常用方法
返回值型別 | 方法 | 解釋 |
---|---|---|
boolean | add(E e) | 向列表的尾部新增指定的元素(可選操作) |
boolean | addAll(Collection<? extends E> c) | 將指定 collection 中的所有元素都新增到此 collection 中(可選操作) |
void | clear() | 移除此 collection 中的所有元素(可選操作) |
boolean | contains(Object o) | 判斷集合是否包含此元素,包含返回true |
boolean | equals(Object o) | 比較此 collection 與指定物件是否相等 |
int | hashCode() | 返回此 collection 的雜湊碼值 |
boolean | isEmpty() | 如果此 collection 不包含元素,則返回 true |
Iterator<E> | iterator() | 返回在此 collection 的元素上進行迭代的迭代器 |
boolean | remove(Object o) | 刪除第一次出現在集合的指定元素,返回值為被刪除的元素(如果存在) |
int | size() | 返回列表中的元素數 |
Object[] | toArray() | 返回按適當順序包含列表中的所有元素的陣列(不常用) |
一、List集合
List 就是列表的意思,它是Collection 的一種,即繼承了 Collection 介面,以定義一個允許重複項的有序集合。該介面不但能夠對列表的一部分進行處理,還添加了面向位置(索引)的操作。List 是按物件的進入順序進行儲存物件,而不做排序或編輯操作。它除了擁有Collection介面的所有的方法外還擁有一些其他的方法。
面向位置(索引)的操作包括插入某個元素或 Collection 的功能,還包括獲取、除去或更改元素的功能。在 List 中搜索元素可以從列表的頭部或尾部開始,如果找到元素,還將報告元素所在的位置。
List介面子實現類的特點
- ArrayList:底層結構是陣列,增刪慢,查詢快(執行緒不安全,效率高)
- Vector:底層結構是陣列,增刪,查詢都很慢(執行緒安全,因此查詢效率比ArrayList要低)
- LinkedList:內部是連結串列資料結構,,增刪元素的速度很快(執行緒不安全)
List集合特有的常用方法
返回值型別 | 方法 | 解釋 |
---|---|---|
boolean | addAll(Collection<? extends E> c) | 按照迭代器返回的元素順序,將指定集合插入到指定集合中 |
boolean | addAll(int index, Collection<? extends E> c) | 從指定的位置開始,將指定 collection 中的所有元素插入到此列表中 |
E | get(int index) | 返回列表中指定位置的元素 |
int | indexOf(Object o) | 返回該元素第一次出現在集合中的索引值;若不包含該元素,則返回 -1 |
int | lastIndexOf(Object o) | 返回該元素最後一次出現在集合中的索引值;若不包含該元素,則返回 -1 |
ListIterator<E> | listIterator() | 返回此列表元素的列表迭代器(按適當順序) |
E | remove(int index) | 根據索引刪除元素,返回值為被刪除的元素 |
E | set(int index, E element) | 根據索引,修改集合中的元素,返回值為替換前的元素 |
常用方法演示
public void test01() {
ArrayList<String> list = new ArrayList<>();
list.add("三國演義");
list.add("西遊記");
list.add("水滸傳");
list.add("紅樓夢");
Iterator<String> ite = list.iterator();
while (ite.hasNext()) {
String next = ite.next();
// 判斷當前元素是否是"西遊記"
if (next.equals("西遊記")) {
// 根據索引修改當前元素為 "吳承恩"
list.set(list.indexOf(next), "吳承恩");
}
// 輸出結果:三國演義 西遊記 水滸傳 紅樓夢
System.out.print(next + "\t");
}
System.out.println();
// 將集合list轉換成Object陣列
Object[] arr = list.toArray();
for (int i = 0; i < arr.length; i++) {
String str = (String) arr[i];
// 輸出結果:三國演義 吳承恩 水滸傳 紅樓夢
System.out.print(str + "\t");
}
}
注意:集合中的元素必須是物件,不能是基本資料型別(JDK 1.5後提供自動拆裝箱)
Collection集合的remove(obj)方法和Iterator介面中的remove()方法的使用
public void test02() {
List<String> list1 = new ArrayList<>();
List<String> list2 = new ArrayList<>();
list1.add("三國演義");
list1.add("西遊記");
list1.add("水滸傳");
list1.add("紅樓夢");
Iterator<String> ite = list1.iterator();
while (ite.hasNext()) {
String next = ite.next();
// 判斷當前元素是否是"西遊記"
if (next.equals("西遊記")) {
// 移除當前元素"西遊記"
//list.remove(next); //報錯,併發修改異常ConcurrentModificationException
// 使用Iterator的方法移除元素不會報錯
ite.remove();
}
}
list2.addAll(list1);
System.out.println("list1 = " + list1);// list1 = [三國演義, 水滸傳, 紅樓夢]
System.out.println("list2 = " + list2);// list2 = [三國演義, 水滸傳, 紅樓夢]
}
注意:迭代器遍歷集合時,使用Collection集合的remove(obj)方法會報併發修改異常java.util.ConcurrentModificationException,
但使用Iterator介面中的remove()方法,程式執行正常。
出現異常 java.util.ConcurrentModificationException的原因及解決辦法?
原因:在迭代過程中,使用了List集合的方法對元素進行操作。導致迭代器並不知道集合中的變化,容易引發資料的不確定性
解決辦法:
- 在迭代時,不要使用集合的方法操作元素
- 使用普通的for迴圈遍歷集合
- 使用ListIterator迭代器操作元素,解決了使用Iterator迭代過程中可能會發生的錯誤情況(後面會講)
1.1、ArrayList集合特點及方法
特點:資料儲存的結構是陣列結構。元素增刪慢,查詢快,由於日常開發中使用最多的功能為查詢資料、遍歷資料,所以ArrayList是最常用的集合。
常用方法:全部繼承自List介面
1.2、LinkedList集合的特點及方法
特點:資料儲存的結構是連結串列結構。元素增刪快,查詢慢。實際開發中對一個集合元素的新增與刪除經常涉及到首尾操作,而LinkedList提供了大量首尾操作的方法
常用方法:
返回值型別 | 方法 | 解釋 |
---|---|---|
void | addFirst(E e) | 將指定元素插入此列表的開頭 |
void | addLast(E e) | 將指定元素新增到此列表的結尾 |
E | getFirst() | 返回此列表的第一個元素(連結串列為空,丟擲NoSuchElementException) |
E | getLast() | 返回此列表的最後一個元素 |
E | removeFirst() | 移除並返回此列表的第一個元素 |
E | removeLast() | 移除並返回此列表的最後一個元素 |
E | peekFirst() | 獲取但不移除此列表的第一個元素(連結串列為空,返回null) |
E | pollFirst() | 獲取但不移除此列表的第一個元素(列表為空,返回 null) |
利用LinkedList集合特點模擬一個堆疊或者佇列資料結構
堆疊:先進後出 First In Last Out
佇列:先進先出 First In First Out
/**
* 利用LinkedList集合特點模擬一個堆疊
* 堆疊:先進後出 First In Last Out
*/
@Test
public void test05() {
LinkedList<String> lklist = new LinkedList<>();
lklist.addLast("one");
lklist.addLast("two");
lklist.addLast("three");
lklist.addLast("four");
lklist.addLast("five");
Iterator<String> ite = lklist.iterator();
while (ite.hasNext()) {
String next = ite.next();
System.out.print(next + " ");// one two three four five
}
}
/**
* 利用LinkedList集合特點模擬佇列資料結構
* 佇列:先進先出 First In First Out
*/
@Test
public void test06() {
LinkedList<String> lklist = new LinkedList<>();
lklist.addFirst("one");
lklist.addFirst("two");
lklist.addFirst("three");
lklist.addFirst("four");
lklist.addFirst("five");
Iterator<String> ite = lklist.iterator();
while (ite.hasNext()) {
String next = ite.next();
System.out.print(next + " "); // five four three two one
}
}
1.3、Vector集合的特點及方法(被ArrayList取代)
特點:資料儲存的結構是陣列結構,為JDK中最早提供的集合。Vector集合已被ArrayList替代。列舉Enumeration已被迭代器Iterator替代。
常用方法:
返回值型別 | 方法 | 解釋 |
---|---|---|
void | addElement(E obj) | 將指定的元件新增到此向量的末尾,將其大小增加 1 |
E | elementAt(int index) | 返回指定索引處的元件 |
Enumeration<E> | elements() | 返回此向量的元件的列舉 |
Vector集合對ArrayList集合使用的對比
二、Set介面
Java 中的Set和正好和數學上直觀的集(set)的概念是相同的。Set最大的特性就是不允許在其中存放的元素是重複的。根據這個特點,我們就可以使用Set 這個介面來實現前面提到的關於商品種類的儲存需求。Set 可以被用來過濾在其他集合中存放的元素,從而得到一個沒有包含重複新的集合。
Set介面中的方法和Collection一致,這裡就不列出了
Set介面子實現類的特點
- HashSet:內部資料結構是雜湊表(執行緒不安全)
- LinkHashSet:內部資料結構是連結串列和雜湊表(執行緒不安全)
- TreeSet:內部資料結構是平衡樹(Balanced tree),元素唯一、有序(執行緒不安全)
重寫hashCode()、equals()方法,保證Set集合元素唯一性,原始碼判斷步驟如下
①判斷的是兩個元素的雜湊值是否相同,即hashCode()
如果雜湊值不同,不需要判斷equals(),就可以保證元素的唯一了
如果相同,再判斷兩個物件的內容是否相同,即equals()
注意:hashCode()方法判斷物件的雜湊值是否相同;equals()方法判斷內容是否相同
注意:HashSet儲存JavaAPI中提供的型別元素時,不需要重寫元素的hashCode()和equals()方法,因為這兩個方法,在JavaAPI的每個類中已經重寫,如String類、Integer類等,但是自定義類需要自己重寫hashCode()和equals()方法,否則無法保證元素唯一性。
下面程式碼體現了Set集合的唯一性
/**
* 利用Set集合元素唯一性移除List集合中重複元素
* String類已經重寫hashCode()和equals()方法
*/
@Test
public void test03() {
Collection<String> set = new HashSet<>();
Collection<String> list = new ArrayList<>();
for (int i = 5; i > 0; i--) {
list.add(i + "");
}
list.add("1");
list.add("3");
list.add("5");
System.out.println("list = " + list);// 輸出結果:list = [5, 4, 3, 2, 1, 1, 3, 5]
set.addAll(list);
System.out.println("set = " + set);// 輸出結果:set = [1, 2, 3, 4, 5]
}
疑惑:set = [1, 2, 3, 4, 5]的輸出結果有點疑惑,set集合自動將結果排序了,查看了下Integer類實現了Comparable介面
2.1、HashSet的特點及方法
特點:資料儲存的結構是雜湊表。元素存取無序,集合元素唯一,元素並不是按照存入時的順序(和List顯然不同) 是按照雜湊值確定存放在HashSet集合的位置,因此也是按照雜湊值取資料的
常用方法:全部實現自Set介面
2.2、LinkHashSet的特點及方法
特點:連結串列和雜湊表組合的一個數據儲存結構,因此元素存取有序、且保證元素唯一性
常用方法:全部實現自Set介面
public void test07() {
Set<String> set = new LinkedHashSet<String>();
set.add("三國演義");
set.add("西遊記");
set.add("水滸傳");
set.add("紅樓夢");
set.add("西遊記");
set.add("三國演義");
Iterator it = set.iterator();
while (it.hasNext()) {
System.out.print(it.next() + "\t");// 三國演義 西遊記 水滸傳 紅樓夢
}
}
2.3、TreeSet的特點及方法
特點:TreeSet集合的底層是二叉樹進行排序的,集合元素唯一性
常用方法:
TreeSet判斷元素唯一性的方式:根據比較方法的返回結果判斷,是0,就是相同元素;不是0,元素不相同
TreeSet對元素進行排序的方式
- 元素自身具備比較性:元素實現Comparable介面,重寫compareTo方法
- 容器具備比較性:使用帶參構造建立TreeSet(Collection<? extends E> c) ,實現compare(T o1, T o2)方法
注意:當Comparable比較方式和Comparator比較方式同時存在時,以Comparator的比較方式為主。
/**
* 驗證TreeSet集合的唯一、排序
*/
@Test
public void test08() {
TreeSet<String> ts = new TreeSet<>();
ts.add("5");
ts.add("2");
ts.add("3");
ts.add("4");
ts.add("1");
ts.add("5");
Iterator<String> ite = ts.iterator();
while (ite.hasNext()) {
Object next = ite.next();
System.out.print(next + " ");// 輸出結果:1 2 3 4 5
}
}
三、總結(集合框架中常用類比較)
看到array,就要想到角標
看到link,就要想到first,last
看到hash,就要想到hashCode,equals
看到tree,就要想到兩個介面Comparable,Comparator