Java核心知識體系1:泛型機制詳解
Java核心知識體系2:註解機制詳解
Java核心知識體系3:異常機制詳解
Java核心知識體系4:AOP原理和切面應用
Java核心知識體系5:反射機制詳解
我們來簡單解讀下上面這個框架圖:
完成對上面框架的整體介紹之後,我們接著對每個類別進行詳細的分析。
Collection介面是處理物件集合的根介面,其中定義了很多對元素進行操作的方法。Collection介面有兩個主要的子介面List和Set,注意Map不是Collection的子介面,這個要牢記。
Collection介面中的方法如下:
其中,有幾個比較常用的方法,比如方法add()新增一個元素到集合中,addAll()將指定集合中的所有元素新增到集合中,contains()方法檢測集合中是否包含指定的元素,toArray()方法返回一個表示集合的陣列。
另外,Collection中有一個iterator()函數,它的作用是返回一個Iterator介面。通常,我們通過Iterator迭代器來遍歷集合。ListIterator是List介面所特有的,在List介面中,通過ListIterator()返回一個ListIterator物件。
Collection介面有兩個常用的子介面,下面會詳細介紹。
List集合代表一個有序集合,集合中每個元素都有其對應的順序索引。List集合允許使用重複元素,可以通過索引來存取指定位置的集合元素。
List介面繼承於Collection介面,它可以定義一個允許重複的有序集合。因為List中的元素是有序的,所以我們可以通過使用索引(元素在List中的位置,類似於陣列下標)來存取List中的元素,這類似於Java的陣列。
List介面為Collection直接介面。List所代表的是有序的Collection,即它用某種特定的插入順序來維護元素順序。使用者可以對列表中每個元素的插入位置進行精確地控制,同時可以根據元素的整數索引(在列表中的位置)存取元素,並搜尋列表中的元素。實現List介面的集合主要有:ArrayList、LinkedList、Vector、Stack。
ArrayList是一個動態陣列,也是我們最常用的集合。它允許任何符合規則的元素插入甚至包括null。每一個ArrayList都有一個初始容量(10),該容量代表了陣列的大小。隨著容器中的元素不斷增加,容器的大小也會隨著增加。在每次向容器中增加元素的同時都會進行容量檢查,當快溢位時,就會進行擴容操作。所以如果我們明確所插入元素的多少,最好指定一個初始容量值,避免過多的進行擴容操作而浪費時間、效率。
size、isEmpty、get、set、iterator 和 listIterator 操作都以固定時間執行。add 操作以分攤的固定時間執行,也就是說,新增 n 個元素需要 O(n) 時間(由於要考慮到擴容,所以這不只是新增元素會帶來分攤固定時間開銷那樣簡單)。
ArrayList擅長於隨機存取。同時ArrayList是非同步的。
同樣實現List介面的LinkedList與ArrayList不同,ArrayList是一個動態陣列,而LinkedList是一個雙向連結串列。所以它除了有ArrayList的基本操作方法外還額外提供了get,remove,insert方法在LinkedList的首部或尾部。
由於實現的方式不同,LinkedList不能隨機存取,它所有的操作都是要按照雙重連結串列的需要執行。在列表中索引的操作將從開頭或結尾遍歷列表(從靠近指定索引的一端)。這樣做的好處就是可以通過較低的代價在List中進行插入和刪除操作。
與ArrayList一樣,LinkedList也是非同步的。如果多個執行緒同時存取一個List,則必須自己實現存取同步。一種解決方法是在建立List時構造一個同步的List:
List list = Collections.synchronizedList(new LinkedList(...));
與ArrayList相似,但是Vector是同步的。所以說Vector是執行緒安全的動態陣列。它的操作與ArrayList幾乎一樣。
的
Stack繼承自Vector,實現一個後進先出的堆疊。Stack提供5個額外的方法使得Vector得以被當作堆疊使用。基本的push和pop 方法,還有peek方法得到棧頂的元素,empty方法測試堆疊是否為空,search方法檢測一個元素在堆疊中的位置。Stack剛建立後是空棧。
Set是一種不包括重複元素的Collection。它維持它自己的內部排序,所以隨機存取沒有任何意義。與List一樣,它同樣允許null的存在但是僅有一個。由於Set介面的特殊性,所有傳入Set集合中的元素都必須不同,同時要注意任何可變物件,如果在對集合中元素進行操作時,導致element1.equals(element2)為true,則必定會產生資料衝突的問題。Set介面有三個具體實現類,分別是
Set是一種不包含重複的元素的Collection,無序,即任意的兩個元素element1和element2都有element1.equals(element2)為false,Set最多可以有一個null元素。需要注意的是,雖然Set中元素沒有順序性,但是元素在set中的位置是由該元素的HashCode決定的,所以具體的位置其實是固定的。
此外需要說明一點,在set介面中的不重複是有特殊要求的。
舉一個例子:物件A和物件B,本來是不同的兩個物件,正常情況下它們是能夠放入到Set裡面的,但是如果物件A和B的都重寫了hashcode和equals方法,並且重寫後的hashcode和equals方法是相同的話。那麼A和B是不能同時放入到Set集合中去的,也就是Set集合中的去重和hashcode與equals方法直接相關。
為了更好地理解,請看下面的例子:
private static void setWork() {
Set<String> set = new HashSet<>();
set.add("Brand1");
set.add("Brand2");
set.add("Brand1");
System.out.println("Set Size:" + set.size());
System.out.println("Set Elements:" + set.toString());
//再次新增一個字串物件 Brand2,然後通過equals方法比較,發現是相等的,所以新增失敗返回false
boolean result = set.add(new String("Brand2"));
System.out.println(result);
System.out.println(set);
}
執行結果:
Set Size:2
Set Elements:[Brand1, Brand2]
false
[Brand1, Brand2]
可以看出,因為有hashcode和equals方法,用來比較指向的字串物件所儲存的字串是否相等,所以第二個Brand1加進去是無效的。
程式通過new關鍵字來建立新的字串物件Brand2,使用==運運算元判斷返回false,使用equals方法比較返回true,所以同樣不能新增到Set集合中,最終還是兩個元素。
HashSet 是一個沒有重複元素的集合。它是由HashMap實現的,不保證元素的順序(這裡所說的沒有順序是指:元素插入的順序與輸出的順序不一致),而且HashSet允許使用null 元素。HashSet是非同步的,如果多個執行緒同時存取一個雜湊set,而其中至少一個執行緒修改了該set,那麼它必須保持外部同步。 HashSet按Hash演演算法來儲存集合的元素,因此具有很好的存取和查詢效能。
HashSet的實現方式大致如下,通過一個HashMap儲存元素,元素是存放在HashMap的Key中,而Value統一使用一個Object物件。
HashSet使用和理解中容易出現的誤區:
LinkedHashSet繼承自HashSet,其底層是基於LinkedHashMap來實現的,有序,非同步。LinkedHashSet集合同樣是根據元素的hashCode值來決定元素的儲存位置,但是它同時使用連結串列維護元素的次序。這樣使得元素看起來像是以插入順序儲存的,也就是說,當遍歷該集合時候,LinkedHashSet將會以元素的新增順序存取集合的元素。
TreeSet是一個有序集合,其底層是基於TreeMap實現的,非執行緒安全。TreeSet可以確保集合元素處於排序狀態。TreeSet支援兩種排序方式,自然排序和客製化排序,其中自然排序為預設的排序方式。當我們構造TreeSet時,若使用不帶引數的建構函式,則TreeSet的使用自然比較器;若使用者需要使用自定義的比較器,則需要使用帶比較器的引數。
注意:TreeSet集合不是通過hashcode和equals函數來比較元素的.它是通過compare或者comparaeTo函數來判斷元素是否相等.compare函數通過判斷兩個物件的id,相同的id判斷為重複元素,不會被加入到集合中。
Map與List、Set介面不同,它是由一系列鍵值對組成的集合,提供了key到Value的對映。同時它也沒有繼承Collection。在Map中它保證了key與value之間的一一對應關係。也就是說一個key對應一個value,所以它不能存在相同的key值,當然value值可以相同。
以雜湊表資料結構實現,查詢物件時通過雜湊函數計算其位置,它是為快速查詢而設計的,其內部定義了一個hash表陣列(Entry[] table),元素會通過雜湊轉換函數將元素的雜湊地址轉換成陣列中存放的索引,如果有衝突,則使用雜湊連結串列的形式將所有相同雜湊地址的元素串起來,可能通過檢視HashMap.Entry的原始碼它是一個單連結串列結構。
LinkedHashMap是HashMap的一個子類,它保留插入的順序,如果需要輸出的順序和輸入時的相同,那麼就選用LinkedHashMap。
LinkedHashMap是Map介面的雜湊表和連結列表實現,具有可預知的迭代順序。此實現提供所有可選的對映操作,並允許使用null值和null鍵。此類不保證對映的順序,特別是它不保證該順序恆久不變。
LinkedHashMap實現與HashMap的不同之處在於,後者維護著一個執行於所有條目的雙重連結列表。此連結列表定義了迭代順序,該迭代順序可以是插入順序或者是存取順序。
根據連結串列中元素的順序可以分為:按插入順序的連結串列,和按存取順序(呼叫get方法)的連結串列。預設是按插入順序排序,如果指定按存取順序排序,那麼呼叫get方法後,會將這次存取的元素移至連結串列尾部,不斷存取可以形成按存取順序排序的連結串列。
注意,此實現不是同步的。如果多個執行緒同時存取連結的雜湊對映,而其中至少一個執行緒從結構上修改了該對映,則它必須保持外部同步。
由於LinkedHashMap需要維護元素的插入順序,因此效能略低於HashMap的效能,但在迭代存取Map裡的全部元素時將有很好的效能,因為它以連結串列來維護內部順序。
TreeMap 是一個有序的key-value集合,非同步,基於紅黑樹(Red-Black tree)實現,每一個key-value節點作為紅黑樹的一個節點。TreeMap儲存時會進行排序的,會根據key來對key-value鍵值對進行排序,其中排序方式也是分為兩種,一種是自然排序,一種是客製化排序,具體取決於使用的構造方法。
自然排序:TreeMap中所有的key必須實現Comparable介面,並且所有的key都應該是同一個類的物件,否則會報ClassCastException異常。
客製化排序:定義TreeMap時,建立一個comparator物件,該物件對所有的treeMap中所有的key值進行排序,採用客製化排序的時候不需要TreeMap中所有的key必須實現Comparable介面。
TreeMap判斷兩個元素相等的標準:兩個key通過compareTo()方法返回0,則認為這兩個key相等。
如果使用自定義的類來作為TreeMap中的key值,且想讓TreeMap能夠良好的工作,則必須重寫自定義類中的equals()方法,TreeMap中判斷相等的標準是:兩個key通過equals()方法返回為true,並且通過compareTo()方法比較應該返回為0。
Iterator的定義如下:
public interface Iterator<E> {}
Java的Iterator(迭代器)是一個設計模式,它使你可以遍歷一個容器(如列表,集合,佇列等)。它提供了一種方法來順序存取聚合物件的元素,而不需要暴露該物件的內部表示。
Iterator提供的API介面如下:
import java.util.*;
public class Main {
public static void main(String[] args) {
// 建立一個ArrayList物件
List<String> list = new ArrayList<>();
list.add("Hello");
list.add("World");
list.add("Java");
// 獲取該ArrayList的迭代器
Iterator<String> it = list.iterator();
// 使用迭代器遍歷列表中的元素
while(it.hasNext()) {
String element = it.next();
System.out.println(element);
if ("Java".equals(element)) {
it.remove();
}
}
// 移除之後的ArrayList物件
System.out.println("after remove element 「java」: " + list);
}
}
輸出結果如下:
Hello
World
Java
remove java element : [Hello, World]
需要注意的點如下:
ListIterator是一個功能更加強大的迭代器, 它繼承於Iterator介面,只能用於各種List型別的存取。它提供了在列表中插入和刪除元素的方法,以及使用hasPrevious()和previous()方法在迭代過程中向前和向後遍歷列表的功能。
以下是ListIterator的主要方法:
public interface ListIterator<E> extends Iterator<E> {
boolean hasNext();
E next();
boolean hasPrevious();
E previous();
int nextIndex();
int previousIndex();
void remove();
void set(E e);
void add(E e);
}
由以上定義我們可以推出ListIterator可以:
使用範例:
public static void listIteratorWork() {
// 建立一個 ArrayList
List<String> list = new ArrayList<>();
list.add("Element A");
list.add("Element B");
list.add("Element C");
System.out.println("當前列表 : " + list);
// 獲取 ListIterator 物件
ListIterator<String> listIterator = list.listIterator();
// 使用 hasNext() 和 next() 方法迭代列表
System.out.println("逐一遍歷 : ");
while (listIterator.hasNext()) {
System.out.println(listIterator.next() + ", " + listIterator.previousIndex() + ", " + listIterator.nextIndex());
}
// 在迭代過程中使用 add() 方法新增元素
listIterator.add("Element D");
System.out.println("新增一個元素之後:" + list);
// 在迭代過程中使用 set() 方法進行元素修改
listIterator = list.listIterator(1);
System.out.print("修改一個元素之後:");
while (listIterator.hasNext()) {
if ("Element D".equals(listIterator.next())) {
listIterator.set("Element replace");
}
}
System.out.println(list);
}
輸出結果如下:
當前列表 : [Element A, Element B, Element C]
逐一遍歷 :
Element A, 0, 1
Element B, 1, 2
Element C, 2, 3
新增一個元素之後:[Element A, Element B, Element C, Element D]
修改一個元素之後:[Element A, Element B, Element C, Element replace]
LinkedHashMap儲存了記錄的插入順序,在用Iterator遍歷LinkedHashMap時,先得到的記錄肯定是先插入的,也可以在構造時用帶引數,按照應用次數排序。在遍歷的時候會比HashMap慢。
TreeMap實現SortMap介面,內部實現是紅黑樹。能夠把它儲存的記錄根據鍵排序,預設是按鍵值的升序排序,也可以指定排序的比較器,當用Iterator 遍歷TreeMap時,得到的記錄是排過序的。TreeMap不允許key的值為null。非同步的。
Set不允許包含相同的元素,如果試圖把兩個相同元素加入同一個集合中,add方法返回false。
Set判斷兩個物件相同不是使用==運運算元,而是根據equals方法。也就是說,只要兩個物件用equals方法比較返回true,Set就不會接受這兩個物件。
HashSet有以下特點:
LinkedHashSet集合同樣是根據元素的hashCode值來決定元素的儲存位置,但是它同時使用連結串列維護元素的次序。這樣使得元素看起來像是以插入順序儲存的,也就是說,當遍歷該集合時候,LinkedHashSet將會以元素的新增順序存取集合的元素。
LinkedHashSet在迭代存取Set中的全部元素時,效能比HashSet好,但是插入時效能稍微遜色於HashSet。
TreeSet是SortedSet介面的唯一實現類,TreeSet可以確保集合元素處於排序狀態。TreeSet支援兩種排序方式,自然排序和客製化排序,其中自然排序為預設的排序方式。向TreeSet中加入的應該是同一個類的物件。
TreeSet判斷兩個物件不相等的方式是兩個物件通過equals方法返回false,或者通過CompareTo方法比較沒有返回0。
Java中的Collection和Collections都是用於處理集合的類,但它們有一些重要的區別。
繼承關係:Collection是所有集合類的根介面,它定義了集合的基本操作,比如新增元素、刪除元素等。Collections是一個幫助類,它提供了靜態方法來操作和操作集合,比如排序、查詢等。Collections類通過實現和範例化集合類的各種基本操作,讓集合類的操作更加簡單。
用法:Collection通常用於定義集合類的基本操作,而Collections則提供了各種靜態方法來操作和操作集合。Collections類中包含了很多有用的靜態方法,比如排序、查詢、複製等。