博客
关于我
Java集合源码分析之List(一):超级接口List
阅读量:270 次
发布时间:2019-03-01

本文共 5389 字,大约阅读时间需要 17 分钟。

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

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.

List特有方法

我们关注其不同于Collection的方法,主要有以下这些:

//在指定位置,将指定的集合插入到当前的集合中boolean addAll(int index, Collection
c);//这是一个默认实现的方法,会通过Iterator的方式对每个元素进行指定的操作default void replaceAll(UnaryOperator
operator) { Objects.requireNonNull(operator); final ListIterator
li = this.listIterator(); while (li.hasNext()) { li.set(operator.apply(li.next())); }}//排序,依据指定的规则对当前集合进行排序,可以看到,排序是通过Arrays这个工具类完成的。default void sort(Comparator
c) { Object[] a = this.toArray(); Arrays.sort(a, (Comparator) c); ListIterator
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
listIterator();//从指定位置开始,返回一个ListIteratorListIterator
listIterator(int index);//返回一个子集合[fromIndex, toIndex),非结构性的修改返回值会反映到原表,反之亦然。//如果原表进行了结构修改,则返回的子列表可能发生不可预料的事情List
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.

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.

大致意思是说,要实现一个不可修改的集合,只需要复写getsize就可以了。要实现一个可以修改的集合,还需要复写set方法,如果要动态调整大小,就必须再实现addremove方法。

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

//在AbstractCollection中,add方法默认会抛出异常,//而在这里是调用了add(int index, E e)方法,但这个方法也是没有实现的。//这里默认会把元素添加到末尾。public boolean add(E e) {    add(size(), e);    return true;}//同上,这个只需要进行一次遍历即可public boolean addAll(int index, Collection
c) { //... }

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

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

public Iterator
iterator() { return new Itr();}

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

另外一个就是ListIterator

public ListIterator
listIterator() { return listIterator(0);}

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

public ListIterator
listIterator(final int index) { rangeCheckForAdd(index); return new ListItr(index);}

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

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

//寻找一个元素首次出现的位置,只需要从前往后遍历,找到那个元素并返回其位置即可。public int indexOf(Object o) {    ListIterator
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
it = listIterator(fromIndex); for (int i=0, n=toIndex-fromIndex; i

接下来还有两块内容比较重要,一个是关于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
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://heka.baihongyu.com/

你可能感兴趣的文章
NIFI1.21.0_java.net.SocketException:_Too many open files 打开的文件太多_实际操作---大数据之Nifi工作笔记0051
查看>>
NIFI1.21.0_Mysql到Mysql增量CDC同步中_日期类型_以及null数据同步处理补充---大数据之Nifi工作笔记0057
查看>>
NIFI1.21.0_Mysql到Mysql增量CDC同步中_补充_更新时如果目标表中不存在记录就改为插入数据_Postgresql_Hbase也适用---大数据之Nifi工作笔记0059
查看>>
NIFI1.21.0_NIFI和hadoop蹦了_200G集群磁盘又满了_Jps看不到进程了_Unable to write in /tmp. Aborting----大数据之Nifi工作笔记0052
查看>>
NIFI1.21.0最新版本安装_连接phoenix_单机版_Https登录_什么都没改换了最新版本的NIFI可以连接了_气人_实现插入数据到Hbase_实际操作---大数据之Nifi工作笔记0050
查看>>
NIFI1.21.0通过Postgresql11的CDC逻辑复制槽实现_指定表多表增量同步_增删改数据分发及删除数据实时同步_通过分页解决变更记录过大问题_02----大数据之Nifi工作笔记0054
查看>>
NIFI1.21.0通过Postgresql11的CDC逻辑复制槽实现_指定表多表增量同步_插入修改删除增量数据实时同步_通过分页解决变更记录过大问题_01----大数据之Nifi工作笔记0053
查看>>
NIFI1.21.0通过Postgresql11的CDC逻辑复制槽实现_指定表或全表增量同步_实现指定整库同步_或指定数据表同步配置_04---大数据之Nifi工作笔记0056
查看>>
NIFI1.23.2_最新版_性能优化通用_技巧积累_使用NIFI表达式过滤表_随时更新---大数据之Nifi工作笔记0063
查看>>
NIFI从MySql中增量同步数据_通过Mysql的binlog功能_实时同步mysql数据_根据binlog实现数据实时delete同步_实际操作04---大数据之Nifi工作笔记0043
查看>>
NIFI从MySql中增量同步数据_通过Mysql的binlog功能_实时同步mysql数据_配置binlog_使用处理器抓取binlog数据_实际操作01---大数据之Nifi工作笔记0040
查看>>
NIFI从MySql中增量同步数据_通过Mysql的binlog功能_实时同步mysql数据_配置数据路由_实现数据插入数据到目标数据库_实际操作03---大数据之Nifi工作笔记0042
查看>>
NIFI从MySql中增量同步数据_通过Mysql的binlog功能_实时同步mysql数据_配置数据路由_生成插入Sql语句_实际操作02---大数据之Nifi工作笔记0041
查看>>
NIFI从MySql中离线读取数据再导入到MySql中_03_来吧用NIFI实现_数据分页获取功能---大数据之Nifi工作笔记0038
查看>>
NIFI从MySql中离线读取数据再导入到MySql中_不带分页处理_01_QueryDatabaseTable获取数据_原0036---大数据之Nifi工作笔记0064
查看>>
NIFI从MySql中离线读取数据再导入到MySql中_无分页功能_02_转换数据_分割数据_提取JSON数据_替换拼接SQL_添加分页---大数据之Nifi工作笔记0037
查看>>
NIFI从PostGresql中离线读取数据再导入到MySql中_带有数据分页获取功能_不带分页不能用_NIFI资料太少了---大数据之Nifi工作笔记0039
查看>>
nifi使用过程-常见问题-以及入门总结---大数据之Nifi工作笔记0012
查看>>
NIFI分页获取Mysql数据_导入到Hbase中_并可通过phoenix客户端查询_含金量很高的一篇_搞了好久_实际操作05---大数据之Nifi工作笔记0045
查看>>
NIFI分页获取Postgresql数据到Hbase中_实际操作---大数据之Nifi工作笔记0049
查看>>