zoukankan      html  css  js  c++  java
  • 第十一章 持有对象1

    Foreach与迭代器

    自学java以来,我用到最方便的遍历方式莫属foreach了,也仅仅会用它,知道它能遍历数组还能便利集合(除Map外)。

    foreach能遍历集合是在Java SE5才出现的,Java SE5引入了新的被称为Iterable的接口(java.lang.Iterable),这个接口仅包含一个能够产生Iterator的iterator()方法,并且Iterable接口被foreach用来在序列中移动。因此如果你创建了任何实现Iterable的类,都可以将他用于foreach语句中。

    既然除Map外的所有集合(Collection对象)都能使用foreach,可想而知,Collection接口肯定是实现了Iterable接口。在Collection或其导出类中肯定对iterator()方法进行了重写,然后产生一个Iterator对象。

    源码中其他不相干的我且删掉:

    package java.util;
    
    import java.util.function.Predicate;
    import java.util.stream.Stream;
    import java.util.stream.StreamSupport;
    
    public interface Collection<E> extends Iterable<E> {/**
         * Returns an iterator over the elements in this collection.  There are no
         * guarantees concerning the order in which the elements are returned
         * (unless this collection is an instance of some class that provides a
         * guarantee).
         *
         * @return an <tt>Iterator</tt> over the elements in this collection
         */
        Iterator<E> iterator();
    
    }

    以最常用的ArrayList分析(已删减):

    public class ArrayList<E> extends AbstractList<E>
            implements List<E>, RandomAccess, Cloneable, java.io.Serializable
    {
    
        public Iterator<E> iterator() {
            return new Itr();
        }
    
    
        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;
    
            Itr() {}
    
            public boolean hasNext() {
                return 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];
            }
    
        }
    }

    iterator方法返回的是一个实现了Iterator<E>接口的内部类,没有使用匿名内部类的原因可想而知,Itr内部类肯定需要被再次使用。ArrayList实现了iterator()方法,该方法提供了对ArrayList的迭代。所以foreach对ArrayList的迭代即是间接的调用了iterator方法,实现遍历,从代码中你也可以看到为什么foreach只能从前向后遍历,它只有next()方法。至于Set接口下的导出类看上去很复杂,但是本质上都是一样,在它们内部也必定以某种方式实现了iterator方法。

    foreach对于Collection的遍历是对Iterable接口的移动,那foreach对数组的遍历是不是也对Iterable接口的移动?数组作为最基本最常用的存储方式,你找不到任何它是否实现了Iterable接口的说明,但是可以用一个例子测一下:

    package mvn.text;
    
    import java.util.Arrays;
    
    public class TestForeach {
        public static void main(String[] args) {
            Integer[] i = {1,2,3,4,5};
            
            //测试ArrayList
            test(Arrays.asList(i));
            
            //测试数组
            //test(i);
        }
        
        public static <T> void test(Iterable<T> itr) {
            for (T t : itr) {
                System.out.print(t + " ");
            }
        }
    }

     把数组直接代进test函数里发现,编译都通不过。这说明不存在任何从数组到Iterable的自动转换。

    那foreach是如何是实现数组的遍历?

    猜想:java的设计者们是否是在使用foreach遍历数组时直接将其转换为普通for循环for(int i = 0 ; i < str.length ; i++) { } ?至少看起来这样转换更加合理一些,扩展了对数组的遍历方式,就像使用适配器模式一样,给普通的for循环替换成另一种接口foreach的样式,但根本上还是使用普通for循环而已。

    前进时,请别遗忘了身后的脚印。
  • 相关阅读:
    Android 数据库框架 DBFlow 的使用
    Android进阶AIDL使用自定义类型
    Android进阶之AIDL的使用详解
    RecyclerView实现拖动排序和滑动删除功能
    RecyclerView的刷新分页
    RecyclerView 的 Item 的单击事件
    RecyclerView 的简单使用
    AutoCompleteTextView的简单使用
    Spinner的简单实用
    黎曼猜想
  • 原文地址:https://www.cnblogs.com/liudaihuablogs/p/9226340.html
Copyright © 2011-2022 走看看