Java™ 教程(List介面)
List介面
List 是一個有序的 Collection (有時稱為序列),列表可能包含重複元素,除了從 Collection
繼承的操作之外, List
介面還包括以下操作:
- 位置訪問 — 根據列表中的數字位置操縱元素,這包括
get
、set
、add
、addAll
和remove
等方法。 - 搜尋 — 搜尋列表中的指定物件並返回其數字位置,搜尋方法包括
indexOf
和lastIndexOf
。 - 迭代 — 擴充套件
Iterator
語義以利用列表的順序性,listIterator
方法提供此行為。 - 範圍檢視 —
sublist
方法對列表執行任意範圍操作。
Java平臺包含兩個通用的 List
實現, ArrayList ,通常是效能更好的實現,而 LinkedList 在某些情況下提供更好的效能。
集合操作
假設你已經熟悉它們,那麼從 Collection
繼承的操作都可以完成你期望它們做的事情,如果你不熟悉 Collection
,現在是閱讀Collection介面部分的好時機, remove
操作始終從列表中刪除指定元素的第一個匹配項, add
和 addAll
操作始終將新元素附加到列表的末尾,因此,以下語法將一個列表連線到另一個列表。
list1.addAll(list2);
這是這個語法的非破壞性形式,它產生第三個 List
,其中包含附加到第一個列表的第二個列表。
List<Type> list3 = new ArrayList<Type>(list1); list3.addAll(list2);
請注意,此語法在其非破壞性形式中利用了 ArrayList
的標準轉換建構函式。
這是一個將一些名稱聚合到 List
中的示例(JDK 8及更高版本):
List<String> list = people.stream() .map(Person::getName) .collect(Collectors.toList());
與 Set 介面一樣, List
強化了對 equals
和 hashCode
方法的需求,因此可以比較兩個 List
物件的邏輯相等性,而不考慮它們的實現類,如果兩個 List
物件包含相同順序的相同元素,則它們是相等的。
位置訪問和搜尋操作
基礎的位置訪問操作是 get
、 set
、 add
和 remove
( set
和 remove
操作返回被覆蓋或刪除的舊值),其他操作( indexOf
和 lastIndexOf
)返回列表中指定元素的第一個或最後一個索引。
addAll
操作從指定位置開始插入指定 Collection
的所有元素,元素按指定 Collection
的迭代器返回的順序插入,此呼叫是 Collection
的 addAll
操作的位置訪問模擬。
這是在 List
中交換兩個索引值的一個小方法。
public static <E> void swap(List<E> a, int i, int j) { E tmp = a.get(i); a.set(i, a.get(j)); a.set(j, tmp); }
當然,有一個很大的區別,這是一個多型演算法:它交換任何 List
中的兩個元素,無論其實現型別如何,這是另一種使用前面 swap
方法的多型演算法。
public static void shuffle(List<?> list, Random rnd) { for (int i = list.size(); i > 1; i--) swap(list, i - 1, rnd.nextInt(i)); }
此演算法包含在Java平臺的 Collections 類中,使用指定的隨機源隨機置換指定的列表,這有點微妙:它從底部向上執行列表,反覆將隨機選擇的元素交換到當前位置。不像大多數天真的洗牌嘗試,這是公平的(假設一個公平的隨機源,所有排列都有相同的可能性)和快速(需要完全 list.size()-1
交換),以下程式使用此演算法以隨機順序列印其引數列表中的單詞。
import java.util.*; public class Shuffle { public static void main(String[] args) { List<String> list = new ArrayList<String>(); for (String a : args) list.add(a); Collections.shuffle(list, new Random()); System.out.println(list); } }
事實上,這個程式可以更短、更快, Arrays 類有一個名為 asList
的靜態工廠方法,它允許將陣列視為 List
,此方法不會複製陣列, List
中的更改會寫入陣列,反之亦然。生成的 List
不是通用 List
實現,因為它沒有實現(可選) add
和 remove
操作:陣列不可調整大小。利用 Arrays.asList
並呼叫 shuffle
的庫版本(使用預設的隨機源),你將得到以下 微小程式 ,其行為與前一個程式相同。
import java.util.*; public class Shuffle { public static void main(String[] args) { List<String> list = Arrays.asList(args); Collections.shuffle(list); System.out.println(list); } }
迭代器
正如你所期望的那樣, List
的 iterator
操作返回的 Iterator
以適當的順序返回列表的元素, List
還提供了一個更豐富的迭代器,稱為 ListIterator
,它允許你在任一方向遍歷列表、在迭代期間修改列表、並獲取迭代器的當前位置。
ListIterator
從 Iterator
繼承的三個方法( hasNext
、 next
和 remove
)在兩個介面中完全相同, hasPrevious
和 previous
操作和 hasNext
和 next
的很相似,前一個操作引用(隱式)遊標之前的元素,而後者引用遊標之後的元素, previous
操作向後移動游標,而 next
向前移動游標。
這是在列表中向後迭代的標準語法。
for (ListIterator<Type> it = list.listIterator(list.size()); it.hasPrevious(); ) { Type t = it.previous(); ... }
請注意前面的語法中 listIterator
的引數, List
介面有兩種形式的 listIterator
方法,不帶引數的形式返回位於列表開頭的 ListIterator
,帶有 int
引數的形式返回一個位於指定索引處的 ListIterator
。索引引用初始呼叫 next
返回的元素,對 previous
的初始呼叫將返回索引為 index-1
的元素,在長度為 n
的列表中, index
有 n+1
個有效值,從 0
到 n
(包括 n
)。
直觀地說,遊標總是在兩個元素之間 — 一個將通過呼叫 previous
返回,一個將通過呼叫 next
返回。 n+1
個有效索引值對應於元素之間的 n+1
個間隙,從第一個元素之前的間隙到最後一個元素之後的間隙,下圖顯示了包含四個元素的列表中的五個可能的遊標位置。