zoukankan      html  css  js  c++  java
  • 集合---list

       Iterable 是所有集合的超类, collection继承了iterable ,而list和set又继承了 collection,而在Iterable中定义了一个iterator()方法返回一个迭代器Iterator

    而 Iterator是一个超类接口,为各种容器提供了公共的操作接口,里边有 hasNext(),next(),remove()三个方法

        有子接口ListIterator和XMLEventReader

      在ArrayList中的使用  

         List<String> list=new ArrayList<>();
              list.add("abc");
              list.add("edf");
              list.add("ghi");
              for(Iterator<String> it=list.iterator();it.hasNext();)
              {
                  System.out.println(it.next());
              }

        在ArrayList内部定义了一个内部类Itr,该类实现了Iterator接口。

          在Itr中,有三个变量分别是,cursor:表示下一个元素的索引位置,lastRet:表示上一个元素的索引位置,expectModCount:预期被修改的次数

            

      关于遍历是不就可以删除集合中元素的问题:

        如果在上边的for循环中增加list.remove(“abc”),会出现ConcurrentModificationException异常。

        因为在你迭代之前,迭代器已经被通过list.itertor()创建出来了,如果在迭代的过程中,又对list进行了改变其容器大小的操作,那么Java就会给出异常。

          因为此时Iterator对象已经无法主动同步list做出的改变,Java会认为你做出这样的操作是线程不安全的,就会给出善意的提醒(抛出                                    ConcurrentModificationException异常)

          ArrayList中的源码实现        

            private class Itr implements Iterator<E> {
              int cursor; // index of next element to return
              int lastRet = -1; // index of last element returned; -1 if no such
              int expectedModCount = modCount;

              public boolean hasNext() {
                return cursor != size;    //当cursor不等于size时,表示仍有索引元素

              }

              @SuppressWarnings("unchecked")
              public E next() {
                checkForComodification();
                int i = cursor;
                if (i >= size)
                  throw new NoSuchElementException();
                Object[] elementData = ArrayList.this.elementData;
                if (i >= elementData.length)
                  throw new ConcurrentModificationException();
                cursor = i + 1;
                return (E) elementData[lastRet = i];
              }

              public void remove() {
                if (lastRet < 0)
                  throw new IllegalStateException();
                checkForComodification();

                try {
                  ArrayList.this.remove(lastRet);
                  cursor = lastRet;
                  lastRet = -1;
                  expectedModCount = modCount;
                  } catch (IndexOutOfBoundsException ex) {
                    throw new ConcurrentModificationException();
                  }
                }

              @Override
              @SuppressWarnings("unchecked")
              public void forEachRemaining(Consumer<? super E> consumer) {
                 Objects.requireNonNull(consumer);
                 final int size = ArrayList.this.size;
                 int i = cursor;
                 if (i >= size) {
                  return;
                 }
                final Object[] elementData = ArrayList.this.elementData;
                if (i >= elementData.length) {
                  throw new ConcurrentModificationException();
                }
                while (i != size && modCount == expectedModCount) {
                consumer.accept((E) elementData[i++]);
                }
                // update once at end of iteration to reduce heap write traffic
                cursor = i;
                lastRet = i - 1;
                checkForComodification();
              }

              final void checkForComodification() {
                if (modCount != expectedModCount)
                  throw new ConcurrentModificationException();
              }
          }

      通过查看源码发现原来检查并抛出异常的是checkForComodification()方法。在ArrayList中modCount是当前集合的版本号,  

        每次修改(增、删)集合都会加1;expectedModCount是当前迭代器的版本号,在迭代器实例化时初始化为modCount。我们看到在                                                 checkForComodification()方法中就是在验证modCount的值和expectedModCount的值是否相等,

        所以当你在调用了ArrayList.add()ArrayList.remove()时,只更新了modCount的状态,而迭代器中的expectedModCount未同步,

           因此才会导致再次调用Iterator.next()方法时抛出异常。

      但是为什么使用Iterator.remove()就没有问题呢?通过源码高亮的行发现,在Iterator的remove()中同步了expectedModCount的值,所以当你下次再调用next()的时候,检查不会抛出异常。

      

    for循环与迭代器的对比:

      * 效率上各有各的优势:

        ArrayList对随机访问比较快,而for循环中使用的get()方法,采用的即是随机访问的方法,因此在ArrayList里for循环快。

        LinkedList则是顺序访问比较快,Iterator中的next()方法采用的是顺序访问方法,因此在LinkedList里使用Iterator较快。

        主要还是要依据集合的数据结构不同的判断。

     
  • 相关阅读:
    费马小定理
    Big Number阶乘位数计算(斯特林公式)
    V
    矩阵快速幂求斐波那契
    奇迹
    缘分
    求导
    拓扑排序
    线段树
    单调栈
  • 原文地址:https://www.cnblogs.com/xp0813/p/11074104.html
Copyright © 2011-2022 走看看