【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

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