黑马程序员技术交流社区

标题: 关于List迭代的小问题。 [打印本页]

作者: wyqs92    时间: 2014-5-18 21:56
标题: 关于List迭代的小问题。
本帖最后由 wyqs92 于 2014-5-19 21:36 编辑
  1. package myreview;


  2. import java.util.ArrayList;
  3. import java.util.Iterator;
  4. import java.util.List;
  5. import java.util.ListIterator;

  6. public class day18test2 {

  7.         public static void main(String[] args) {
  8.         /*
  9.          * list集合练习
  10.          *
  11.          */
  12.                 List list=new ArrayList();
  13.                 list.add("abc1");
  14.                 list.add("abc2");
  15.                 list.add("abc3");
  16.                 list.add("abc4");
  17.                 list.add("abc5");
  18.                 list.add("abc6");
  19.                 System.out.println("原集合"+list);
  20.         
  21.                 for(ListIterator it=list.listIterator();it.hasNext();){
  22.                         Object obj=new Object();
  23.                         obj=it.next();
  24.                         if(obj.equals("abc2")){
  25.                                 it.add("dddd");//为了避免出现并发修改异常,使用了
  26. listIterator() ,但这里为什么不能是list.add("dddd")而是it.add("dddd")了?
  27.                         }
  28.                         
  29.                 }
  30.                 System.out.println(list);
  31.         }        

  32. }
复制代码

复制代码



作者: zhrnghgwsws    时间: 2014-5-18 22:22
这种情况下,你要么使用集合的方法,要么使用迭代器的方法。不能同时让集合的方法和迭代器的方法对其进行操作。像你说的会出现并发修改异常。
所以在这个例子中,你在使用迭代器的过程中,要对元素进行操作,就只能使用迭代器的add()方法,即:it.add().
如果使用List.add()就是并发修改异常。
作者: pandapan    时间: 2014-5-18 22:42
这个是信息同步的问题啦,同学。
1. 迭代器的问题,咱们看看jdk1.6 api怎么描述的吧
  1. public ListIterator<E> listIterator(int index)
  2. 返回列表中元素的列表迭代器(按适当顺序),从列表的指定位置开始。指定的索引表示 next 的初始调用所返回的第一个元素。previous 方法的初始调用将返回索引比指定索引少 1 的元素。
  3. 此实现返回 ListIterator 接口的直接实现,扩展了由 iterator() 方法返回的 Iterator 接口的实现。ListIterator 实现依赖于底层实现列表的 get(int)、set(int, E)、add(int, E) 和 remove(int) 方法。
  4. 注意,除非重写列表的 remove(int)、set(int, E) 和 add(int, E) 方法,否则此实现返回的列表迭代器将抛出 UnsupportedOperationException 来响应其 remove、set 和 add 方法。

  5. 根据 (protected) modCount 字段规范中的描述,在面临并发修改时,可以使此实现抛出运行时异常。
复制代码


个人的见解:其实说白了,就是ArrayList内部实现了一个ListIterator接口的一个类,就是说我调用这个方法,就是把ArrayList中所有信息传递给这个子类。
2. 理解了这个之后呢,我们再说为什么使用ListIterator接口可以,使用ArrayList的方法却不行。
其实是迭代器的实现的问题。
一个一个说。
2.1假如说我们使用ArrayList的删除或者增加方法,在此之前呢,我们的ArrayList的数据已经给了ArrayList内部实现了一个ListIterator接口的类,调用这些方法呢,ArrayList内部没有实现通知的机制,即不会去通知已经生成的实现ListIterator接口的类,原因是这样的,假如说实现了通知机制,这是存在问题的,原因如下:
   我们知道是、,使用ArrayList是可以删除ArrayList存在的任何元素的,假如我们删除的是在迭代器中已经便利过的,那么即使我们通知迭代器也是无济于事的,因为都已经迭代完了,所以数据时存在问题的。
2.2 为什么我们使用接口的方法就没问题的,因为实现ListIterator接口的类呢,实现了通知的机制,那么你可能会问,这个就不会出现这个问题呢,答案是不会的,我们看看迭代器的api说明,
2.2.1
    public void remove()从列表中移除由 next 或 previous 返回的最后一个元素(可选操作)。对于每个 next 或 previous 调用,只能执行一次此调用。只有在最后一次调用 next 或 previous 之后,尚未调用 ListIterator.add 时才可以执行该调用。
2.2.2
void add(E e)将指定的元素插入列表(可选操作)。该元素直接插入到 next 返回的下一个元素的前面(如果有),或者 previous 返回的下一个元素之后(如果有);如果列表没有元素,那么新元素就成为列表中的唯一元素。新元素被插入到隐式光标前:不影响对 next 的后续调用,并且对 previous 的后续调用会返回此新元素(此调用把调用 nextIndex 或 previousIndex 所返回的值增加 1)。
add方法本来就是就最后增加元素,所以不可能存在问题。
remove方法操作的都是当前元素(这就是指针的问题啦,对于我们使用的previous,next,iterator都会指向我们的结果),没有涉及到已经遍历的元素,所以是可行的。
以下是小小的一个案例,楼主可以先考虑考虑执行的结果是什么?这个是比较有意思的一道题目,我自己写的,希望能够帮到你.

  1. public class ArrayListTest {

  2.         public static void main(String[] args) {
  3.                 // TODO Auto-generated method stub
  4.                 ArrayList<String> list = new ArrayList<String>();
  5.                 list.add("str1");
  6.                 list.add("str2");
  7.                 list.add("str3");
  8.                 list.add("str4");
  9.                 list.add("str5");
  10.                 for(ListIterator iterator=list.listIterator();iterator.hasNext();){
  11.                         System.out.println("for each start");
  12.                         if(iterator.hasPrevious()){
  13.                                 System.out.println("enter if condition");
  14.                                 System.out.println(iterator.previous());
  15.                         }
  16.                 }
  17.                 System.out.println("over");
  18.         }

  19. }
复制代码





欢迎光临 黑马程序员技术交流社区 (http://bbs.itheima.com/) 黑马程序员IT技术论坛 X3.2