Java基礎系列(四十一):集合之List
前言
List
是繼承自Collection
的一個子介面,它提供了一個有序的集合,在這個集合中我們可以使用索引去獲取集合中的值,同時,我們也可以通過迭代器去訪問集合中的元素,第一種方法被稱為隨機訪問,因為我們可以按照任意的順序去訪問元素,而使用迭代器就必須順序的去訪問元素。
結構圖
可以看出List
的結構圖也非常簡單,只是簡單的繼承了Collection
,這裡不再進行過多的闡述,我們來看一下原始碼。
原始碼
package java.util;
import java.util.function.UnaryOperator;
public interface List<E> extends Collection<E> {
// Query Operations
int size();
boolean isEmpty();
boolean contains(Object o);
Iterator<E> iterator();
Object[] toArray();
<T> T[] toArray(T[] a);
// Modification Operations
boolean add (E e);
boolean remove(Object o);
// Bulk Modification Operations
boolean containsAll(Collection<?> c);
boolean addAll(Collection<? extends E> c);
boolean addAll(int index, Collection<? extends E> c);
boolean removeAll(Collection<?> c);
boolean retainAll(Collection<?> c);
default void replaceAll(UnaryOperator<E> operator) {
Objects.requireNonNull(operator);
final ListIterator<E> li = this.listIterator();
while (li.hasNext()) {
li.set(operator.apply(li.next()));
}
}
@SuppressWarnings({"unchecked", "rawtypes"})
default void sort(Comparator<? super E> c) {
Object[] a = this.toArray();
Arrays.sort(a, (Comparator) c);
ListIterator<E> i = this.listIterator();
for (Object e : a) {
i.next();
i.set((E) e);
}
}
void clear();
// Comparison and hashing
boolean equals(Object o);
int hashCode();
// Positional Access Operations
E get(int index);
E set(int index, E element);
void add(int index, E element);
E remove(int index);
// Search Operations
int indexOf(Object o);
int lastIndexOf(Object o);
// List Iterators
ListIterator<E> listIterator();
/**
* 這裡返回的列表迭代器是第一次呼叫next返回的給定索引的元素,也就是說,這個迭代器指向的索引為n的元素前面的位置。
*/
ListIterator<E> listIterator(int index);
// View
List<E> subList(int fromIndex, int toIndex);
@Override
default Spliterator<E> spliterator() {
return Spliterators.spliterator(this, Spliterator.ORDERED);
}
}
可以看到相比於它的父介面Collection
,並沒有發生很大的改動,但是由於List
是一個有序的集合,所以提供了一些基於索引進行的操作:
get(int index)
:獲取該集合中索引等於index的元素
set(int index, E element)
:將該集合中索引等於index的元素賦值為element
add(int index, E element)
:在集合中索引等於index的位置將element插入,並將當前處於該位置的元素及其後續元素的索引加1。
remove(int index)
:刪除指定索引(index)位置的元素,並將處於該位置後面的元素索引減1
indexOf(Object o)
:獲取物件o在集合中的索引
lastIndexOf(Object o)
:獲取物件o在集合中最後一次出現的索引值,如果集合中不存在這個物件,返回-1。
同時,提供了一個Iterator
的子介面ListIterator
,基於這個迭代器,我們實現了兩個預設方法replaceAll(UnaryOperator<E> operator)
和sort(Comparator<? super E> c)
。
replaceAll(UnaryOperator<E> operator)
這裡和String
類中replaceAll()
方法並不相同,這裡的接收引數是一個函式式介面,我們來看一下這個函式式介面的原始碼:
package java.util.function;
@FunctionalInterface
public interface UnaryOperator<T> extends Function<T, T> {
/**
* Returns a unary operator that always returns its input argument.
*
* @param <T> the type of the input and output of the operator
* @return a unary operator that always returns its input argument
*/
static <T> UnaryOperator<T> identity() {
return t -> t;
}
}
通過翻譯我們可以知道,這個函式式介面繼承了Function<T,T>
,傳入的是一個值,返回的是一個經過操作符之後的值,我接下來來寫一個小李子來講解一下用法:
List<String> strList = new ArrayList<>();
strList.add("Hungary");
strList.add("Foolish");
strList.replaceAll(t -> "Stay " + t);
strList.forEach(s -> System.out.println(s));
列印結果為
Stay Hungary Stay Foolish
而sort(Comparator<? super E> c)
傳入的同樣是一個函式式介面,我們可以自定義排序規則後,呼叫這個方法進行排序:
List<Human> humans = Lists.newArrayList(new Human("Sarah", 10), new Human("Jack", 12));
humans.sort((Human h1, Human h2) -> h1.getName().compareTo(h2.getName()))
(PS:Java 8 提供了Lambda語法糖,給人帶來一種非常舒服的程式設計體驗,建議大家多多使用)
這裡是Arrays.sort
的原始碼,可以看到使用了歸併演算法和TimSort
演算法來進行排序,後面關於演算法和資料結構的知識會詳細對這些內容進行講解,這裡只作為一個瞭解~
public static <T> void sort(T[] a, Comparator<? super T> c) {
if (c == null) {
sort(a);
} else {
if (LegacyMergeSort.userRequested)
legacyMergeSort(a, c);
else
TimSort.sort(a, 0, a.length, c, null, 0, 0);
}
}
ListIterator
前面我們已經提過,ListIterator
作為Iterator
的子介面,給有序的集合List
提供了一個連結串列結構下的迭代器,接下來,我們來看一下ListIterator
的原始碼:
package java.util;
public interface ListIterator<E> extends Iterator<E> {
// Query Operations
boolean hasNext();
E next();
boolean hasPrevious();
E previous();
int nextIndex();
int previousIndex();
// Modification Operations
void remove();
void set(E e);
void add(E e);
}
可以看出和Iterator
不同的是,ListIterator
新增了一些基於連結串列資料結構的操作以及可以用來反向遍歷連結串列的方法:
hasPrevious()
:當反向迭代列表時,還有可供訪問的元素,返回true。
previous()
:返回前一個物件,如果已經到達了列表的頭部,丟擲一個NoSuchElementException
異常
nextIndex()
:返回下一次呼叫next方法將返回的元素索引
previousIndex()
:返回下一次呼叫previous方法將返回的元素索引
add(E newElement)
:在當前位置前新增一個元素。
set(E newElement)
:用新元素取代next或previous上次訪問的元素。如果在next或previous上次呼叫之後列表結構被修改了,將丟擲一個IllegalStateException
異常。
下節預告
下一節,我們會去深入的學習AbstractList
。