java Conllection介面及其實現類
Java集合大致可分為Set、List和Map三種體系,其中Set代表無序、不可重複的集合;List代表有序、重複的集合;
而Map則代表具有對映關係的集合。Java 5之後,增加了Queue體系集合,代表一種佇列集合實現。Java集合框架主要由Collection和Map兩個根介面及其子介面、實現類組成。
Collection介面介面是Set、List和Queue介面的父介面,方法有
- add(Object o):新增元素
- addAll(Collection c):新增c集合中所有元素
- clear():刪除Collection物件中的所有元素
- contains(Object o):是否包含o元素,底層呼叫為equals()方法
- containsAll(Collectionc):是否包含集合c中的所有元素
- iterator():返回Iterator物件,用於遍歷集合中的元素
- remove(Object o):移除元素
- removeAll(Collection c):從集合中移出它和C物件相同的元素。而對於A中含有而B中不含有的物件,不移除。
- retainAll(Collection c):相當於求與c的交集
- size():返回元素個數
- toArray():把集合轉換為一個數組
-
hashCode():返回字串的雜湊碼。
Collection介面中並未重寫toString(),toString的重寫是在它的實現類AbstractCollection中實現的。
Set子介面
Set介面是Collection介面的子類,其繼承了所有方法,HashSet集合則實現了Set介面,其內部儲存資料時依靠雜湊表,一個類似陣列和連結串列的結合體。設定空集合時,存在預設的容量和載入因子,再用HashSet物件呼叫add方法時,其實是先比較其Hash值,若是沒有的話,則直接新增到集合中,若有的話,則再equals下比較其內容(因為有可能內容不一樣,但是其Hash值一樣),若是內容不一樣,則在這個地址下新增(鏈式),若是一樣的話,則丟掉。注意就保證了其的唯一性。(以後定義變數時,都需要重寫其hashcode和equals方法)至於LinkedHashSet則在HashSet基礎上保證了其的有序性(取出和存入順序一樣)。
HashSet:
由HashSet的原始碼可知,HashSet底層就是一個HashMap。我們在往HashSet中儲存資料的時候,HashSet新增的元素是存放在HashMap的key位置上,而value取了預設常量PRESENT,是一個空物件。
HashSet底層的資料結構是一個雜湊表,存在HashSet中的元素應該重寫其hashCode()方法,故存在HashMap中的key,應該 重寫其hashCode()方法。HashSet集合不能保證迭代順序與元素的儲存順序相同。
擴容機制:預設初始容量為16。載入因子為0.75:即當 元素個數 超過 容量長度的0.75倍 時,進行擴容。擴容增量:原容量的 1 倍
LinkedHashSet類
LinkedHashSet具有set集合不重複的特點,同時具有可預測的迭代順序,也就是我們插入的順序。因為是HashSet的子類,所以也是保證元素唯一的,與HashSet的原理一樣。
此實現與 HashSet 的不同之處在於,LinkedHashSet 維護著一個運行於所有條目的雙重連結列表。此連結列表定義了迭代順序,該迭代順序可為插入順序或是訪問順序。
SortSet介面與TreeSet類
TreeSet為SortSet的一個實現類,該類可以按照元素大小進行排序,但是存入的物件必須實現Comparable<T>介面並對其比較方法進行重寫,可以比較出物件比較後的大小。或者使用java.util.Comparator;來單獨編寫一個比較器,建立TreeSet集合的時候提供這個比較器,如果未實現介面或提供比較器會丟擲ClassCastException。
新增方法:
- first():返回第一個元素
- last():返回最後一個元素
- lower(Object o):返回指定元素之前的元素
- higher(Obect o):返回指定元素之後的元素
- subSet(fromElement, toElement):返回子集合
EnumSet類
EnumSet這是一個用來操作Enum的集合,EnumSet中的所有元素都必須是指定列舉型別的列舉值,它是一個抽象類,有兩個繼承類:JumboEnumSet和RegularEnumSet。在使用的時候,需要確定列舉型別。它的特點也是速度非常快。
EnumSet是一個抽象類,不能直接通過new新建,noneOf方法會建立一個指定列舉型別的EnumSet,不含任何元素。建立的EnumSet物件的實際型別是EnumSet的子類,執行緒不安全
List介面
List子介面是有序集合。有索引,包含了一些帶索引的方法,還允許儲存重複的元素。
void add(int index, E element) 在指定 index 索引處理插入元素 element
boolean addAll(int index, Collection<? extends E> c) 在指定 index 索引處理插入集合元素 c
E remove(int index) 刪除指定索引 index 處的元素
E set(int index, E element) 修改指定索引 index 處的元素為 element
E get(int index) + int size() for迴圈遍歷集合中的每一個元素
ListIterator<E> listIterator() 通過列表迭代器遍歷集合中的每一個元素
ListIterator<E> listIterator(int index) 通過列表迭代器從指定索引處開始正向或者逆向遍歷集合中的元素
E get(int index) 獲取指定索引處的元素
int indexOf(Object o) 從左往右查詢,獲取指定元素在集合中的索引,如果元素不存在返回 -1
int lastIndexOf(Object o) 從右往左查詢,獲取指定元素在集合中的索引,如果元素不存在返回 -1
List<E> subList(int fromIndex, int toIndex) 擷取從 fromIndex 開始到 toIndex-1 處的元素
ArrayList
ArrayList 是一個陣列佇列,相當於動態陣列。與Java中的陣列相比,它的容量能動態增長。它繼承於AbstractList,實現了List, RandomAccess, Cloneable, java.io.Serializable這些介面。ArrayList繼承了AbstractList,實現了List。
它是一個數組佇列,提供了相關的新增、刪除、修改、遍歷等功能。
ArrayList實現了RandmoAccess介面,即提供了隨機訪問功能。RandmoAccess是java中用來被List實現,為List提供快速訪問功能的。在ArrayList中,我們即可以通過元素的序號快速獲取元素物件;這就是快速隨機訪問。
ArrayList 實現了Cloneable介面,即覆蓋了函式clone(),能被克隆。
ArrayList 實現java.io.Serializable介面,這意味著ArrayList支援序列化,能通過序列化去傳輸。ArrayList的操作不是執行緒安全的。
擴容機制:當ArrayList不為空時,並且它的大小不超過10時,它的容量都是10.但當大小從10增加到11時,容量變成了15,擴大了1.5倍。
如果ArrayList的容量大於MAX_ARRAY_SIZE,來比較 minCapacity 和 MAX_ARRAY_SIZE,如果minCapacity大於最大容量,則新容量則為Integer.MAX_VALUE,否則,新容量大小則為 MAX_ARRAY_SIZE
即為 Integer.MAX_VALUE - 8。
Vector
Vector 類實現了一個動態陣列。和 ArrayList 很相似,但是兩者是不同的:
- Vector 是同步訪問的。
- Vector 包含了許多傳統的方法,這些方法不屬於集合框架。
Vector 主要用在事先不知道陣列的大小,或者只是需要一個可以改變大小的陣列的情況。
第一種構造方法建立一個預設的向量,預設大小為10;
Vector()
第二種構造方法建立指定大小的向量。
Vector(int size)
第三種構造方法建立指定大小的向量,並且增量用 incr 指定。增量表示向量每次增加的元素數目。
Vector(int size,int incr)
第四種構造方法建立一個包含集合 c 元素的向量:
Vector(Collection c)
Stack
棧是Vector的一個子類,它實現了一個標準的後進先出的棧。它也是執行緒安全的。
堆疊只定義了預設建構函式,用來建立一個空棧。 堆疊除了包括由Vector定義的所有方法,也定義了自己的一些方法。
Stack()除了由Vector定義的所有方法,自己也定義了一些方法:
E push(E item) 把項壓入堆疊頂部
E pop() 移除堆疊頂部的物件,並作為此函式的值返回該物件。
E peek() 檢視堆疊頂部的物件,但不從堆疊中移除它。
boolean empty() 測試堆疊是否為空。
int search(Object o) 返回物件在堆疊中的位置,以 1 為基數。
Linkedlist
它繼承了AbstractSequentialList 類,同時也實現了 Deque 介面
Linkedlist是線性資料結構,其中元素不儲存在連續的位置,每個元素都是具有資料部分和地址部分的獨立物件。元素使用指標和地址進行連結。每個元素被稱為節點。由於插入和刪除的動態性和易用性,它們優於陣列。
它也有一些缺點,比如節點不能直接訪問,我們需要從頭開始,然後通過連結到達我們希望訪問的節點。
為了將元素儲存在連結串列中,我們使用一個雙向連結串列,它提供了一個線性資料結構,並且還用於繼承一個抽象類並實現list和deque介面。
以下情況使用 ArrayList :
- 頻繁訪問列表中的某一個元素。
- 只需要在列表末尾進行新增和刪除元素操作。
以下情況使用 LinkedList :
- 你需要通過迴圈迭代來訪問列表中的某些元素。
- 需要頻繁的在列表開頭、中間、末尾等位置進行新增和刪除元素操作。
Queue子介面
Queue介面與List、Set同一級別,都是繼承了Collection介面。LinkedList實現了Queue介面。
佇列的主要特點是在基本的集合方法之外,還提供特殊的插入、獲取和檢驗操作。每個操作都提供兩個方法,一種返回異常,一種返回null或者false.
佇列一般滿足先進先出規則(FIFO),除了優先佇列(priority queue)和棧(stack),但是棧是FILO(先進後出規則),優先佇列自己定義了排序規則。
佇列不允許插入null元素,但是LinkedList可以
java.ulil.concurrent包提供了阻塞佇列的4個變種。預設情況下,LinkedBlockingQueue的容量是沒有上限的,但是也可以選擇指定其最大容量,它是基於連結串列的佇列,此佇列按 FIFO(先進先出)排序元素。
ArrayBlockingQueue在構造時需要指定容量, 並可以選擇是否需要公平性,如果公平引數被設定true,等待時間最長的執行緒會優先得到處理(其實就是通過將ReentrantLock設定為true來 達到這種公平性的:即等待時間最長的執行緒會先操作)。通常,公平性會使你在效能上付出代價,只有在的確非常需要的時候再使用它。它是基於陣列的阻塞迴圈隊 列,此佇列按 FIFO(先進先出)原則對元素進行排序。
PriorityBlockingQueue是一個帶優先順序的 佇列,而不是先進先出佇列。元素按優先順序順序被移除,該佇列也沒有上限(看了一下原始碼,PriorityBlockingQueue是對 PriorityQueue的再次包裝,是基於堆資料結構的,而PriorityQueue是沒有容量限制的,
與ArrayList一樣,所以在優先阻塞 佇列上put時是不會受阻的。雖然此佇列邏輯上是無界的,但是由於資源被耗盡,所以試圖執行新增操作可能會導致 OutOfMemoryError),但是如果佇列為空,那麼取元素的操作take就會阻塞,所以它的檢索操作take是受阻的。
另外,往入該佇列中的元 素要具有比較能力。
最後,DelayQueue(基於PriorityQueue來實現的)是一個存放Delayed 元素的無界阻塞佇列,只有在延遲期滿時才能從中提取元素。該佇列的頭部是延遲期滿後儲存時間最長的 Delayed 元素。
如果延遲都還沒有期滿,則佇列沒有頭部,並且poll將返回null。當一個元素的 getDelay(TimeUnit.NANOSECONDS) 方法返回一個小於或等於零的值時,則出現期滿,poll就以移除這個元素了。此佇列不允許使用 null 元素。 下面是延遲介面:
- add(E e) 插入一個元素到佇列中,失敗時返回IllegalStateException (佇列容量不夠)
- element() 返回佇列頭部的元素
- offer(E e) 插入一個元素到佇列中,失敗時返回false
- peek() 返回佇列頭部的元素,佇列為空時返回null
- poll() 返回並移除佇列的頭部元素,佇列為空時返回null
- remove() 返回並移除佇列的頭部元素
Deque介面
雙端佇列是一種線性集合,可以從兩端操作的佇列。
- add(E e) 將新元素新增到佇列的尾端(當不超過佇列的容量時)
- addFirst(E e) 將新元素新增到佇列的頭部
- addLast(E e) 將新元素新增到佇列的尾部
- contains(Object o) 雙端佇列是否含有物件o
- descendingIterator()倒敘返回佇列的迭代器
- element() 返回佇列的頭部元素
- getFirst() 獲取頭部元素
- getLast() 獲取尾部元素
- iterator() 迭代佇列
- offer(E e) 將新元素插入到佇列尾部
- offerFirst(E e) 將新元素新增到佇列的頭部
- offerLast(E e) 將新元素新增到佇列的尾部
- peek() 返回佇列的頭部元素
- peekFirst() 獲取頭部元素
- peekLast() 獲取尾部元素
- pool() 返回並移除佇列的頭部元素
- poolFirst() 獲取並移除頭部元素
- poolLast() 獲取並移除尾部元素
- pop() 將一個元素出棧
- push(E e) 講一個元素壓入棧
- remove() 移除佇列的頭部元素
- remove(Object o) 移除佇列中第一個o
- removeFirst() 移除佇列的頭部元素
- removeFirstOccurrence(Object o) 移除佇列中第一個o
- removeLast() 移除佇列的尾部元素
- removeLastOccurrence(Object o) 移除佇列中最後一個o