【JAVA源碼學習】List接口

在這裏插入圖片描述
List接口非常常見,常用的ArrayList,LinkedList等都實現了該接口,因此瞭解該接口定義了什麼方法有助於我們更好的理解其他類和接口。


以下是源碼:

public interface List<E> extends Collection<E> {
    // 查詢操作:
     // 返回 list的數目,若數目超過 Integer中定義的最大值,返回 Interger.MAX_VALUE
    int size();

     // 判斷 list是否爲空
    boolean isEmpty();

     // 判斷 list是否包含特定的對象 o
    boolean contains(Object o);

     // 以適當順序返回該 list中元素的迭代器
    Iterator<E> iterator();
    
     // 將 list中的元素按合適的順序以數組的形式返回
     // 注意返回的對象是新的數組,可被調用者隨意修改
    Object[] toArray();

     // 將 list中的元素按合適的順序以特定元素數組的形式返回
     // 如果傳入的數組數目小於或等於 list的數目,則直接將 a數組的元素進行賦值,否則,重新新建一個合適數組,並賦值給 a
    <T> T[] toArray(T[] a);
    
    
    // 修改操作:
     // 將一個類型爲 E的對象 e加入到 list的末尾
     // 一部分 list的實現類可以允許對象爲 null,一部分不允許,對應的類需在說明文檔中指明約束的條件
    boolean add(E e);

     // 刪除 list中的元素 o,如果有多個,刪除下標更小的(從頭掃描到尾碰到的第一個 o對象)
     // 返回 true代表 list中確實有存在至少一個對象 o,且已刪除
    boolean remove(Object o);
    
    
    // 批量修改操作:
     // 判斷 list中是否包含傳入的集合中的所有元素
    boolean containsAll(Collection<?> c);

     // 將指定集合中的所有元素按指定集合的迭代器(可選操作)返回的順序添加到此列表的末尾。 
     // 如果在操作時修改了指定的集合,則此操作將出現錯誤。 
    boolean addAll(Collection<? extends E> c);

     // 跟上一個函數操作相同,區別在於元素被插入在指定的位置
    boolean addAll(int index, Collection<? extends E> c);

     // 將在特定集合中出現的所有元素,在 list中刪除
     // 如果 list因爲此次函數調用發生改變,返回 true
    boolean removeAll(Collection<?> c);

     // 清除 list中不在集合 c中出現的元素
    boolean retainAll(Collection<?> c);
    
     // 將該列表的每個元素替換爲將運算符應用於該元素的結果
    default void replaceAll(UnaryOperator<E> operator) {
        // 判斷傳入是否爲 Null
        Objects.requireNonNull(operator);
        // 獲得 list的迭代器
        final ListIterator<E> li = this.listIterator();
        // 遍歷整個 list
        while (li.hasNext()) {
            // 將元素替換爲將運算符應用於該元素跟下一元素的結果 
            li.set(operator.apply(li.next()));
        }
    }

     // list接口定義的默認方法,對整個 list進行排序
    @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);
        }
    }

     // 清除 list中的所有元素,調用後整個 list爲空
    void clear();


    // 比較和散列:
     // 判斷兩個 list是否相等。當兩個 list擁有相同的元素且順序相同時,判斷爲 true
     // 注意數目也要相同
    boolean equals(Object o);

     // 返回 list的哈希值
    int hashCode();


    // 位置訪問操作:
     // 返回 list中指定位置的元素
    E get(int index);

     // 用特定值替換 list指定位置的元素的值,返回原先位置的元素
    E set(int index, E element);
    
     // 將特定元素插入到指定位置處,將原位置元素以及右側其他元素都向右移動一位
    void add(int index, E element);

     // 將特定位置的元素刪除,將其右側其他元素向左移動一位
    E remove(int index);


    // 搜索操作:
     // 返回指定元素第一次出現的索引,如果沒有則返回 -1
    int indexOf(Object o);

     // 返回指定元素最後一次出現的索引,如果沒有則返回 -1
    int lastIndexOf(Object o);


    // 列表迭代器:
     // 返回此列表中元素的列表迭代器(按適當順序)
    ListIterator<E> listIterator();

     // 從指定位置開始,返回此列表中元素的列表迭代器
    ListIterator<E> listIterator(int index);


    // 視圖操作:
     // 返回 list裏指定開端(包含),跟末端(不包含)的 list視圖
    List<E> subList(int fromIndex, int toIndex);

     // list接口的默認方法:在 list的元素上創建 Spliterator(用於遍歷和區分源元素的對象)
    @Override
    default Spliterator<E> spliterator() {
        return Spliterators.spliterator(this, Spliterator.ORDERED);
    }
}

補充兩個點:

① 上面List<E> subList(int fromIndex, int toIndex)提到的視圖操作,這裏稍微補充一下:

視圖是指計算機數據庫中的視圖,是一個虛擬表,其內容由查詢定義。同真實的表一樣,視圖包含一系列帶有名稱的列和行數據。

這裏是將 list中的一部分元素,變成一個新的 list,返回給用戶。但這裏要注意,對這個 list的修改,是會修改到原始數據,例如以下代碼:

public class Main {
    public static void main(String[] args) {
        ArrayList<Integer> a = new ArrayList<>();
        a.add(5); 
        a.add(4); 
        a.add(3);
        a.add(2);
        a.add(1);

        List<Integer> b =  a.subList(0, 2);
        for (Integer i : b
             ) {
            System.out.print(i + " ");
        }
        System.out.println();
        
        b.set(0, 55);
        for (Integer i : b
                ) {
            System.out.print(i + " ");
        }
        System.out.println();
        
        for (Integer i : a
                ) {
            System.out.print(i + " ");
        }
        System.out.println();
    }
}

打印的結果爲:
在這裏插入圖片描述
可以發現,原始 list中的數據已經被修改,具體的等在 ArrayList的源碼學習中進行討論。


② 上面提到的默認函數 replaceAll

    default void replaceAll(UnaryOperator<E> operator) {
        // 判斷傳入是否爲 Null
        Objects.requireNonNull(operator);
        // 獲得 list的迭代器
        final ListIterator<E> li = this.listIterator();
        // 遍歷整個 list
        while (li.hasNext()) {
            // 將元素替換爲將運算符應用於該元素跟下一元素的結果 
            li.set(operator.apply(li.next()));
        }
    }

用於對 list中的所有元素,進行一次一元運算符的操作。

查看 UnaryOperator 的源碼:

package java.util.function;

/**
 * 表示對單個操作數的操作,該操作生成與其操作數相同類型的結果。
 * @param <T> 操作數的類型和運算符的結果
 * @since 1.8
 */
@FunctionalInterface
public interface UnaryOperator<T> extends Function<T, T> {

    /**
     * 返回一個總是返回其輸入參數的函數
     * @param <T> 運算符的輸入和輸出的類型
     * @return 一元運算符,始終返回其輸入參數
     */
    static <T> UnaryOperator<T> identity() {
        return t -> t;
    }
}

即,這是一個用於存一元操作符的對象,而對於 apply 方法:

public interface Function<T, R> {
    /**
     * 將此函數應用於給定的參數
     *
     * @param t 函數操作
     * @return 函數結果
     */
    R apply(T t);
}

因此,我們可以推斷:replaceAll 的意思:對 list中的所有對象,都進行一次特定的一元運算符操作,我們可以寫出測試代碼:

    public static void main(String[] args) {
        List<Integer> list = new ArrayList<>();
        list.add(5);
        list.add(4);
        list.add(3);
        list.add(2);

        list.replaceAll(t -> t);
        for (Inte
        ger a : list
             ) {
            System.out.print(a + " ");
        }
        System.out.println();

        list.replaceAll(t -> t + 3);
        for (Integer a : list
                ) {
            System.out.print(a + " ");
        }
        System.out.println();
    }

執行代碼的結果:
在這裏插入圖片描述
其他可以用的操作包括:

t -> t - 2t -> t % 2t -> ~tt -> t / 2

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章