解析java.util集合类源码(SubList)
来源:互联网 发布:cad mac中文破解版 编辑:程序博客网 时间:2024/05/17 02:12
SubList类
在1.6和1.7的api中没有给出SubList的说明,只有subList方法,返回一个List列表的子类列表
public List<E> subList(int fromIndex,int toIndex)但在jdk的源码中,你可以搜到SubList,它在AbstractList类下,却不是内部类
先看下SubList的结构
SubList继承AbstractList抽象类,AbstractList实现了List接口,所以SubList说到底就是一个List的实现类,主要用于返回List的视图,这个视图是原List对象中的一部分,确实是一部分,直接将原List对象引用到新的子视图的List,对子视图进行改变,原List对象也会随之改变
下面就解释为什么会造成这种情况
首先看SubList中的属性域
SubList有4个自己的属相域和1个继承自AbstractList的modCount
private AbstractList<E> l;private int offset;private int size;private int expectedModCount;AbstractList l 就是存放母List的那个引用,当List对象(本编中指类似ArrayList的实现List的对象)调用subList方法时候,会调用abstractList中的subList的实现
//AbstractList中的subList方法 public List<E> subList(int fromIndex, int toIndex) { return (this instanceof RandomAccess ? new RandomAccessSubList<E>(this, fromIndex, toIndex) : new SubList<E>(this, fromIndex, toIndex)); }这里this是多态的,指的是那个外部调用subList方法的那个List对象,先判断this是否实现了RandomAccess接口,实现返回RandomAccessSublist否则返回SubList,通过构造方法将this传给SubList中l属性,在介绍构造方法时细说
int offset 开始子List在母List中的开始位置
int size 记录大小 = toIndex - fromIndex
int expectedModCount 列表的中元素添加、删除的次数,子列表的同步使用
SubList(AbstractList<E> list, int fromIndex, int toIndex) { if (fromIndex < 0) throw new IndexOutOfBoundsException("fromIndex = " + fromIndex); if (toIndex > list.size()) throw new IndexOutOfBoundsException("toIndex = " + toIndex); if (fromIndex > toIndex) throw new IllegalArgumentException("fromIndex(" + fromIndex + ") > toIndex(" + toIndex + ")"); l = list; offset = fromIndex; size = toIndex - fromIndex; expectedModCount = l.modCount; }
SubList的构造方法
做3个对fromIndex和toIndex的检查后,将list 付给l,fromIndex付给offset,原list对象的modCount付给expectedModCount
其实就是将原来的list对象放到SubList中,同时将子列表的开始下标和结束下标付给SubList
public E set(int index, E element) { rangeCheck(index); checkForComodification(); return l.set(index+offset, element); }修改子列表中下标为index 的元素,同时也将原list中的元素修改,rangeCheck检查下标越界,checkFormComodification判断list是否同步
同步:在List对象返回Iterator迭代器后,不能够对List 对象进行(添加、删除)操作,否则modCount++,这时候modeCount不等于expectedmoCount。
这是在一般的List中,但是在SubList中不但要考虑迭代器和List对象的同步问题,还有母列表和子列表的同步问题,下面的checkFormComodification方法将l的modCount和subList中的expectedModCount比较,当List对象通过subList(fromIndex,toIndex)方法获取到SubList后,母List对象又调用add方法,这时母List对象中的modCount++,但子列表中的expectedModCount并没有变,造成不同步抛出异常
private void rangeCheck(int index) { if (index<0 || index>=size) throw new IndexOutOfBoundsException("Index: "+index+ ",Size: "+size); }
private void checkForComodification() { if (l.modCount != expectedModCount) throw new ConcurrentModificationException(); }
检查母列表和子类表的同步
public E get(int index) { rangeCheck(index); checkForComodification(); return l.get(index+offset); }和set方法类似,母列表开始下标是0,子列表开始下标是offset,所以获取母列表中的元素时,应加上offset
public int size() { checkForComodification(); return size; }返回子列表的size
public void add(int index, E element) { if (index<0 || index>size) throw new IndexOutOfBoundsException(); checkForComodification(); l.add(index+offset, element); expectedModCount = l.modCount; size++; modCount++; }将元素添加到子列表的index位置,首先检查是否同步,调用母列表的add(index,e)方法,这时候母列表的modCount会增加,更新子列表中用来判断和母列表同步的变量expectedModCount,子列表的size++,子列表的modCount++
public E remove(int index) { rangeCheck(index); checkForComodification(); E result = l.remove(index+offset); expectedModCount = l.modCount; size--; modCount++; return result; }remove方法与add(index,e)方法类似,调用母列表的remove(index)方法
protected void removeRange(int fromIndex, int toIndex) { checkForComodification(); l.removeRange(fromIndex+offset, toIndex+offset); expectedModCount = l.modCount; size -= (toIndex-fromIndex); modCount++; }与add(index,e)方法相似,调用母列表的removeRange(fromIndex,toIndex)方法
public boolean addAll(Collection<? extends E> c) { return addAll(size, c); } public boolean addAll(int index, Collection<? extends E> c) { if (index<0 || index>size) throw new IndexOutOfBoundsException( "Index: "+index+", Size: "+size); int cSize = c.size(); if (cSize==0) return false; checkForComodification(); l.addAll(offset+index, c); expectedModCount = l.modCount; size += cSize; modCount++; return true; }类似
public Iterator<E> iterator() { return listIterator(); }重写了iterator方法,在SubList中不管调用iterator方法,还是listIterator方法都返回的是ListIterator
public ListIterator<E> listIterator(final int index) { checkForComodification(); if (index<0 || index>size) throw new IndexOutOfBoundsException( "Index: "+index+", Size: "+size); return new ListIterator<E>() { private ListIterator<E> i = l.listIterator(index+offset); public boolean hasNext() { return nextIndex() < size; } public E next() { if (hasNext()) return i.next(); else throw new NoSuchElementException(); } public boolean hasPrevious() { return previousIndex() >= 0; } public E previous() { if (hasPrevious()) return i.previous(); else throw new NoSuchElementException(); } public int nextIndex() { return i.nextIndex() - offset; } public int previousIndex() { return i.previousIndex() - offset; } public void remove() { i.remove(); expectedModCount = l.modCount; size--; modCount++; } public void set(E e) { i.set(e); } public void add(E e) { i.add(e); expectedModCount = l.modCount; size++; modCount++; } }; }listIterator方法返回的是一个ListIterator匿名类
private ListIterator<E> i = l.listIterator(index+offset);
这个ListIterator匿名类本身操作的也是母列表中的listiterator,用i来存储这个参数
其他方法基本都是通过i这个ListIterator来对迭代进行操作,方法类似AbstractList中ListIterator,这个迭代不熟悉请看上一篇博客
更好的理解SubList类,我们可以写段程序,Debug他内部的调用过程
母列表和子列表的不同步:
@Test public void test(){ ArrayList list = new ArrayList(); list.add("ee"); list.add("ee"); list.add("eee"); List subList = list.subList(0, 2); list.add("ee");//母列表元素增加,母列表中的modCount增加,破坏母列表和子列表的同步 Iterator it2 = subList.iterator();//报错,子列表和母列表不同步 }这段代码测试子列表与母列表不同步的问题
list是一个普通的ArrayList对象,subList一个从list中截取的一段子列表,我们从最开始进行debug跟踪,当list.subList()->AbstractList.subList ->这时候new SubList(ps:RandomAccessSubList也是SubList,不细说),将subList中的参数初始化,重要的同步参数expectedModCount = l.modCount = 3,此时SubList中的expectedModCount = 3,list.subList走完,此时 expectedModCount = l.modCount = 3
再看主程序中下条代码list.add(e)->ArrayList.add(e)->ArrayList.ensureCapacity(int minCapacity),这方法中modCount++,这个modCount是母列表中的modCount也就是SubList中 的l.modCount,然后添加元素,list.add(e)走完,此时l.modCount = 4 ,SubList中的expectedModCount =3
当subList.iterator()->SubList.iterator()->SubList.listIterator()->SubList.checkForComodification()这里有段代码
private void checkForComodification() { if (l.modCount != expectedModCount) throw new ConcurrentModificationException(); }用母列表的modCount和SubList中expectedModCount比较相等,expectedModCount是在new SubList()时候被初始化的= 3 ,而l.modCount在list.add()时候++了=4,造成了母列表和子列表的不同步
列表与迭代器的不同步:
修改一下刚才的代码
@Testpublic void test(){ArrayList list = new ArrayList();list.add("ee");list.add("ee");list.add("eee");List subList = list.subList(0, 2);Iterator it2 = subList.iterator();subList.add("在这里会修改母list中的modCount");it2.next();//这会报错,原因母列表的modCount与迭代器中的expecedModCount值不同Iterator it = list.listIterator();list.add("在这里会修改list中的modCount");it.next(); //这会报错,原因母列表的modCount与迭代器中的expecedModCount值不同}
subList方法前面有讲,大体过程和上述相同
当subList.iterator时,在SubList中的iterator在检查同步之后,返回一个ListIterator匿名类,其中有一个参数private ListIterator<E> i = l.listIterator(index+offset);在初始化这匿名类时候,调用母列表的listIterator方法返回一个母列表的迭代器,初始化这个迭代器时,有一个int expectedModCount = modCount,这个expectedModCount是母列表迭代器中的,与SubList中的那个无关,此时母列表迭代器ListIterator中的expectedModCount = 母列表的modCount = 3
当subList.add()时候->AbstractList.add(e)->SubList.add(index,e)这里调用母列表的add方法->ArrayList.add在这里会将母列表中的modCount++ = 4,然后添加元素
再看迭代时的代码it2.next()
it2.next()调用ListIterator匿名类中的next()方法(ps:it2本身就是那个被new出来的匿名类)
public E next() { if (hasNext()) return i.next(); else throw new NoSuchElementException(); }这时使用是母列表的迭代器的next方法,在next方法中checkForComodification()检查同步此时的母列表的modCount = 4,但母列表迭代器的expectedModCount =3 不同步,报错
所以说在List中使用subList要小心,因为本身SubList这个类就是原List的一个视图,改变SubList必定会改变原List
- 解析java.util集合类源码(SubList)
- 解析java.util集合类源码(ArrayList)
- 解析java.util集合类源码(AbstractSequentialList)
- 解析java.util集合类源码(Queue)
- 解析java.util集合类源码(Collection和AbstractCollection篇)
- 解析java.util集合类源码(List和AbstractList篇)
- java.util.List.subList
- java.util.List.subList
- java.util.List.subList
- 使用java.util.List.subList
- java.util.List.subList注意事项
- java.util.List.subList分析
- 解析java.util集合类源码(AbstractList内部类ListIterator和Itr)
- java.util.logging源码解析
- java.util.ArrayList源码解析
- java.util.LinkedList源码解析
- java.util.Vector源码解析
- java.util.Stack源码解析
- 网络编程
- 第6天 二叉树
- MYSQL ERROR 1130 (HY000) 的错误解决方案
- mybatis一对多的策略,嵌套对象分装
- Java基础知识1
- 解析java.util集合类源码(SubList)
- 金火正易圖
- 深入理解java多态性!!(超赞!!作者写的很好)
- 浅谈欧拉图、半欧拉图(Eulerian graph、semi-Eulerian graph)
- 第6天 输入两棵二叉树A和B,判断B是不是A的子结构。
- 布圖詩
- 相遇Qt5
- java7 新特性
- iptables的一些资料