Java容器(持续更新中)

ConcurrentModificationException

在使用List.subList()取得subList后,可以使用subList修改List中的元素,但是如果List中做了修改操作,那么就不能再操作subList了(查询操作也不行),否则将报ConcurrentModificationException。因为List中有个modCount的字段,List每次有修改操作,modCount都会自增。而subList每个操作前都要判断自己的modCount与List的modCount是否相等,不等则报ConcurrentModificationException。修改subList,subList会调用List去执行修改,subList再同步List的modCount;而List修改时,不会去修改subList的信息,如size,modCount等。所以再List修改后,原来的subList需要重新获取。

例子:

List<Gerbil> list = new LinkedList<Gerbil>();
        for(int i=10; i>0; i--){
            list.add(new Gerbil());
        }
        println(list.toString());
        List subList = list.subList(0,5);
        println(subList.toString());
        list.removeAll(subList);
//        list.remove(0);
//        subList.remove(1);
        println(list.toString());

这个例子非常特别,看似list修改后,没有对subList操作。但是再list移除时,会调用subList.contains(),然后调用iterator(),就会检查modCount。

在使用Iterator过程中,也会报ConcurrentModificationException,直接原因也是因为modCount不一致,因为Collection中并没有Iterator的引用,所以Collection修改后,其modCount自增,而Iterator中的modCount未变,导致Iterator检查modCount是否一致时报错。那根本原因是如果Collection中变化了,而Iterator中的信息与Collection不一致,会导致一些问题。比如在iterator.hasNext执行后,Collection删除了一些元素,很可能导致在iterator.next时访问越界。

        List<Gerbil> list = new LinkedList();
        for(int i=10; i>0; i--){
            list.add(new Gerbil());
        }
//foreach语句也是使用iterator的,所以以下操作也会导致报错
//        for(Gerbil g : list){
//            g.hop();
//            list.remove(g);
//        }
        Iterator<Gerbil> iterator = list.iterator();
        while (iterator.hasNext()){
            Gerbil g = iterator.next();//会去检查modCount
            g.hop();
            list.remove(6);//将导致下一个循环周期报错
        }

 

List容器特有的ListIterator

可前后移动,可通过set()改变当前cursor指向的元素,还有add()。创建时可通过int指定开始cursor。下面的例子时将sourceList中的元素反序放在targetList中,注意向listIterator(index)传入的index,如果从后向前遍历,传入的参数时lsit.size(),而从前向后遍历时,是传入0。在调用previous()时,是先减1后再获取元素的,而调用next()时是先获取元素再加1的。

        List<Gerbil> sourceList = new ArrayList<Gerbil>(10);
        List<Gerbil> targetList = new ArrayList<Gerbil>();
        for(int i=10; i>0; i--){
            sourceList.add(new Gerbil());
        }
        targetList.addAll(sourceList);
        ListIterator<Gerbil> sourceIterator = sourceList.listIterator(0);
        ListIterator<Gerbil> targetIterator = targetList.listIterator(targetList.size());
        while (sourceIterator.hasNext() && targetIterator.hasPrevious()){
            targetIterator.previous();
            targetIterator.set(sourceIterator.next());
        }
        println(sourceList.toString());
        println(targetList.toString());

ListIterator的add()和remove(),nextIndex()和previousIndex()

Iterator中有一个index表明当前索引(虽然LinkedList不是使用数组实现,但是仍然可是使用索引),调用next会返回index指向的元素,然后index++;调用previous会index--,然后返回index指向的元素。如果使用add(object),则object插入到index的位置,原来index及其后的元素后移一位,然后index++;调用remove(),则移除index位置的元素,然后index后面的元素前移一位;调用nextIndex(),返回index;调用previousIndex(),返回index-1;

猜你喜欢

转载自blog.csdn.net/b1480521874/article/details/88432016
今日推荐