JAVA集合源码攻坚战(4)——List

前言

根据java 8 的官方文档,Collection接口类下面有三个子接口类,List、Set、Queue。
在这里插入图片描述

List

基础

List接口是定义了一个元素有序的、可重复的、可为null的集合结构。

为什么List中元素是有序的呢?

根据官方文档描述

The user of this interface has precise control over where in the list each element is inserted. The user can access elements by their integer index (position in the list), and search for elements in the list.

大概意思是

该界面的用户可以精确控制列表中每个元素的插入位置。 用户可以通过整数索引(列表中的位置)访问元素,并搜索列表中的元素。

类似于数组,可以根据索引来获取对应位置的元素。
而像Set集合,就无法通过索引来获取元素了。

为什么List中元素可重复呢?

那是因为就算同一个元素存储了多次,但每次存储进去的内存地址都是不同的,看上去是同一个元素,但是在List中存储的位置是不一样的,所以即使有重复元素,对List来说是没有区别的。

数据存储

关于List具体底层的数据结构,这个要根据不同的实现来定。
比如常见的ArrayList,就是类似于数据一样,一开始创建的时候会根据默认大小或者用户指定的大小来开辟一段连续的内存空间,元素就挨个存储进去。
再如LinkedList,就不是开辟一段连续的空间了,而是可以利用分散的内存空间,通过指针来将数据关联起来。

方法

在这里插入图片描述

List的方法可以分为几类:
继承自Collection中的方法不再赘述,这里也还没涉及到具体的实现,等学到实现类再研究。
元素相关

  • E get(int index);
    • 获取指定索引位置的元素
  • E set(int index, E element);
    • 在指定索引位置插入元素
  • E remove(int index);
    • 删除指定索引位置的元素
    • 注意,Collection中的remove方法参数是Object类型,是根据元素去删的,可能会删除多个位置的同一元素
  • boolean addAll(int index, Collection<? extends E> c);
    • 在指定索引位置插入给定集合中的元素

位置相关

  • int indexOf(Object o);
    • 从头开始查找指定元素第一次出现的位置的索引
  • int lastIndexOf(Object o);
    • 从末尾向前查找指定元素第一次出现的位置的索引

迭代

  • ListIterator<E> listIterator();
    • 提供扩展的迭代器ListIterator,将整个list放入迭代器中。
  • ListIterator<E> listIterator(int index);
    • 将从指定索引位置开始到末尾的这一段list数据放入ListIterator迭代器中进行迭代。

集合范围操作

  • List<E> subList(int fromIndex, int toIndex);
    • 根据起始索引和结束索引,截取一段list集合数据,范围包括起始索引,不包括结束索引(包左不包右)

注意调用subList并不会形成新的list,而是会保持对原来list的引用,所以对subList进行操作,会影响到原来的list集合。

栗子

List<String> list = new ArrayList<>();
list.add("a");
list.add("b");
list.add("c");
list.add("d");
list.add("a");
		
System.out.println(list.toString());
		
List<String> subList = list.subList(0, 2);
System.out.println(subList.toString());
subList.clear();
System.out.println(list.toString());

结果:

[a, b, c, d, a]
[a, b]
[c, d, a]

从结果来看,sublist执行了clear()操作后,也把原来的list中对应的元素给清除了。

java 8 新增的方法

  1. replaceAll(UnaryOperator<E> operator)
default void replaceAll(UnaryOperator<E> operator) {
        Objects.requireNonNull(operator);
        final ListIterator<E> li = this.listIterator();
        while (li.hasNext()) {
            li.set(operator.apply(li.next()));
        }
    }

将该列表的每个元素替换为将该运算符应用于该元素的结果。
意思就是再进行元素替换操作时,每次尽心替换,都可以根据传入的operator方法来进行修改,有点类似于python的map方法,对遍历的每个元素都运行指定的函数进行操作。
栗子
main方法:

List<String> list = new ArrayList<>();
		list.add("a");
		list.add("b");
		list.add("c");
		list.add("d");
		list.add("a");
		System.out.println(list);
		System.out.println("=========================");
		MyOperator operator = new MyOperator();
		list.replaceAll(operator);
		System.out.println(list);

操作类:

public class MyOperator implements UnaryOperator<String>{

	@Override
	public String apply(String t) {
		// TODO Auto-generated method stub
		return (String) (t + "111");
	}

}

结果:

[a, b, c, d, a]
=========================
[a111, b111, c111, d111, a111]

从结果看,在遍历list时,每一次都执行了操作类的apply方法。

  1. sort(Comparator<? super E> c)
@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);
        }
    }
  1. Spliterator<E> spliterator()
@Override
    default Spliterator<E> spliterator() {
        return Spliterators.spliterator(this, Spliterator.ORDERED);
    }
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值