Java集合源码分析之List(一):超级接口List_一点课堂(多岸学院)

ListCollection三大直接子接口之一,其中的数据能够经过位置检索,用户能够在指定位置插入数据。List的数据能够为空,能够重复。如下是其文档注释,只看前两段:java

An ordered collection (also known as a sequence). 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.多线程

Unlike sets, lists typically allow duplicate elements. More formally, lists typically allow pairs of elements <tt>e1</tt> and e2 such that e1.equals(e2), and they typically allow multiple null elements if they allow null elements at all. It is not inconceivable that someone might wish to implement a list that prohibits duplicates, by throwing runtime exceptions when the user attempts to insert them, but we expect this usage to be rare.app

List特有方法

咱们关注其不一样于Collection的方法,主要有如下这些:ide

//在指定位置,将指定的集合插入到当前的集合中
boolean addAll(int index, Collection<? extends E> c);

//这是一个默认实现的方法,会经过Iterator的方式对每一个元素进行指定的操做
default void replaceAll(UnaryOperator<E> operator) {
    Objects.requireNonNull(operator);
    final ListIterator<E> li = this.listIterator();
    while (li.hasNext()) {
        li.set(operator.apply(li.next()));
    }
}

//排序,依据指定的规则对当前集合进行排序,能够看到,排序是经过Arrays这个工具类完成的。
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);
    }
}

//获取指定位置的元素
E get(int index);

//修改指定位置元素的值
E set(int index, E element);

//将指定元素添加到指定的位置
void add(int index, E element);

//将指定位置的元素移除
E remove(int index);

//返回一个元素在集合中首次出现的位置
int indexOf(Object o);

//返回一个元素在集合中最后一次出现的位置
int lastIndexOf(Object o);

//ListIterator继承于Iterator,主要增长了向前遍历的功能
ListIterator<E> listIterator();

//从指定位置开始,返回一个ListIterator
ListIterator<E> listIterator(int index);

//返回一个子集合[fromIndex, toIndex),非结构性的修改返回值会反映到原表,反之亦然。
//若是原表进行告终构修改,则返回的子列表可能发生不可预料的事情
List<E> subList(int fromIndex, int toIndex);

经过以上对接口的分析能够发现,Collection主要提供一些通用的方法,而List则针对线性表的结构,提供了对位置以及子表的操做。工具

超级实现类:AbstractList

有了分析AbstractCollection的经验,咱们分析AbstractList就更容易了。首先也看下其文档中强调的部分:学习

To implement an unmodifiable list, the programmer needs only to extend this class and provide implementations for the get(int) and size() methods.ui

To implement a modifiable list, the programmer must additionally override the set(int, E) method (which otherwise throws an UnsupportedOperationException). If the list is variable-size the programmer must additionally override the add(int, E) and remove(int) methods.this

大体意思是说,要实现一个不可修改的集合,只须要复写getsize就能够了。要实现一个能够修改的集合,还须要复写set方法,若是要动态调整大小,就必须再实现addremove方法。线程

而后看下其源码实现了哪些功能吧:code

//在AbstractCollection中,add方法默认会抛出异常,
//而在这里是调用了add(int index, E e)方法,但这个方法也是没有实现的。
//这里默认会把元素添加到末尾。
public boolean add(E e) {
    add(size(), e);
    return true;
}

//同上,这个只须要进行一次遍历便可
public boolean addAll(int index, Collection<? extends E> c) {
    //...   
}

接下来,还有几个方法和IteratorListIterator息息相关,在AbstractList中有具体的实现,咱们先看看它是如何把集合转变成Iterator对象并支持foreach循环的吧。

咱们追踪源码发现,在iterator()方法中直接返回了一个Itr对象

public Iterator<E> iterator() {
    return new Itr();
}

这样咱们就明白了,它是实现了一个内部类,这个内部类实现了Iterator接口,合理的处理hasNextnextremove方法。这个源码就不粘贴啦,其中仅仅在remove时考虑了一下多线程问题,有兴趣的能够本身去看看。

另一个就是ListIterator

public ListIterator<E> listIterator() {
    return listIterator(0);
}

能够看到,listIterator方法依赖于listIterator(int index)方法。有了上边的经验,咱们能够推测,它也是经过一个内部类完成的。

public ListIterator<E> listIterator(final int index) {
    rangeCheckForAdd(index);

    return new ListItr(index);
}

事实证实,和咱们想的同样,AbstractList内部还定义了一个ListItr,实现了ListIterator接口,其实现也很简单,就不粘贴源码啦。

接下来咱们看看,利用这两个实现类,AbstractList都作了哪些事情。

//寻找一个元素首次出现的位置,只须要从前日后遍历,找到那个元素并返回其位置便可。
public int indexOf(Object o) {
    ListIterator<E> it = listIterator();
    if (o==null) {
        while (it.hasNext())
            if (it.next()==null)
                return it.previousIndex();
    } else {
        while (it.hasNext())
            if (o.equals(it.next()))
                return it.previousIndex();
    }
    return -1;
}

//同理,寻找一个元素最后一次出现的位置,只须要从列表最后一位向前遍历便可。
//看到listIterator(int index)方法是能够传递参数的,这个我想咱们均可以照着写出来了。
public int lastIndexOf(Object o) {
    //...
}

//这个方法是把从fromIndex到toIndex之间的元素从集合中删除。
//clear()方法也是调用这个实现的(我认为clear实现意义并不大,由于在其上级AbstractCollection中已经有了具体实现)。
protected void removeRange(int fromIndex, int toIndex) {
    ListIterator<E> it = listIterator(fromIndex);
    for (int i=0, n=toIndex-fromIndex; i<n; i++) {
        it.next();
        it.remove();
    }
}

接下来还有两块内容比较重要,一个是关于SubList的,一个是关于equalshashcode的。

咱们先看看SubList相关的内容。SubList并非新建了一个集合,只是持有了当前集合的引用,而后控制一下用户能够操做的范围,因此在接口定义时就说明了其更改会直接反应到原集合中。SubList定义在AbstractList内部,而且是AbstractList的子类。在AbstractList的基础上增长了对可选范围的控制。

equalshashcode的实现,也关乎咱们的使用。在AbstractList中,这两个方法不只与其实例有关,也和其内部包含的元素有关,因此在定义数据元素时,也应该复写这两个方法,以保证程序的正确运行。这里看下其源码加深一下印象吧。

public boolean equals(Object o) {
    if (o == this)
        return true;
    if (!(o instanceof List))
        return false;

    ListIterator<E> e1 = listIterator();
    ListIterator<?> e2 = ((List<?>) o).listIterator();
    while (e1.hasNext() && e2.hasNext()) {
        E o1 = e1.next();
        Object o2 = e2.next();
        //这里用到了数据元素的equals方法
        if (!(o1==null ? o2==null : o1.equals(o2)))
            return false;
    }
    return !(e1.hasNext() || e2.hasNext());
}
public int hashCode() {
    int hashCode = 1;
    for (E e : this)
        //这里用到了数据元素的hashCode方法
        hashCode = 31*hashCode + (e==null ? 0 : e.hashCode());
    return hashCode;
}

【感谢您能看完,若是可以帮到您,麻烦点个赞~】

更多经验技术欢迎前来共同窗习交流: 一点课堂-为梦想而奋斗的在线学习平台 http://www.yidiankt.com/

![关注公众号,回复“1”免费领取-【java核心知识点】] file

QQ讨论群:616683098

QQ:3184402434

想要深刻学习的同窗们能够加我QQ一块儿学习讨论~还有全套资源分享,经验探讨,等你哦! 在这里插入图片描述

相关文章
相关标签/搜索