Java迭代 : Iterator和Iterable接口

從英文意思去理解

 

Iterable :故名思議,實現了這個接口的集合對象支持迭代,是可迭代的。able結尾的表示 能...樣,能夠作...。
Iterator:   在英語中or 結尾是都是表示 ...樣的人 or ... 者。如creator就是創做者的意思。這裏也是同樣:iterator就是迭代者,咱們通常叫迭代器,它就是提供迭代機制的對象,具體如何迭代,都是Iterator接口規範的。
 
 
 

Iterable

一個集合對象要代表本身支持迭代,能有使用foreach語句的特權,就必須實現Iterable接口,代表我是可迭代的!然而實現Iterable接口,就必需爲foreach語句提供一個迭代器。
這個迭代器是用接口定義的 iterator方法提供的。也就是iterator方法須要返回一個Iterator對象。

 foreach只能用於數組和實現了Iterable接口的類數組

 

//Iterable JDK源碼
//能夠經過成員內部類,方法內部類,甚至匿名內部類去實現Iterator

public
interface Iterable<T> { Iterator<T> iterator(); }

 

 

Iterator

 包含3個方法: hasNext ,  next , remove。remove按需求實現,通常它不多用到,以致於Eclipse接口方法自動補全時,都忽略了remove放方法。ide

一、每次在迭代前   ,先調用hasNext()探測是否迭代到終點(本次還能再迭代嗎?)。
二、next方法不只要返回當前元素,還要後移遊標cursor
三、remove()方法用來刪除最近一次已經迭代出的元素
四、 迭代出的元素是原集合中元素的拷貝(重要)
五、配合foreach使用

 

//Iterator接口的JDK源碼,註釋爲整理建議使用Iterator的正確姿式

public
interface Iterator<E> { boolean hasNext(); //每次next以前,先調用此方法探測是否迭代到終點 E next(); //返回當前迭代元素 ,同時,迭代遊標後移 /*刪除最近一次已近迭代出出去的那個元素。 只有當next執行完後,才能調用remove函數。 好比你要刪除第一個元素,不能直接調用 remove() 而要先next一下( ); 在沒有先調用next 就調用remove方法是會拋出異常的。 這個和MySQL中的ResultSet很相似 */ void remove()
{
throw new UnsupportedOperationException("remove"); } }

 

 

 

 迭代的具體細節

須要理解的地方函數

一、hasNext , next  , remove 的調用順序this

二、迭代出來的是原集合元素拷貝!spa

 

下面是手動迭代的例子,foreach的原理和它同樣。3d

public static void main(String[] args)
{

        List<Integer> li = new ArrayList<>();
        
        li.add(1);
        li.add(2);
        li.add(3);
        
//不使用foreach 而手動迭代 Iterator
<Integer> iter = li.iterator(); //獲取ArrayList 的迭代器 while(iter.hasNext()) //①先探測可否繼續迭代 { System.out.println(iter.next()); //②後取出本次迭代出的元素 //invoke remove() //③最後若是須要,調用remove } }

 

 

AbstractList中實現的迭代器類,能夠借鑑參考。指針

咱們實現本身的迭代器的狀況不多,畢竟JDK集合足夠強大。code

源碼中有一些保護機制,爲了便於理解我刪改了。對象

private class Itr implements Iterator<E> 
{ /*
AbstractList 中實現的迭代器,刪除了一些細節。不影響理解
Itr爲一個priavate成員內部類

*/
int cursor = 0; //立刻等待被迭代元素的index //最近一次,已經被迭代出的元素的index,若是這個元素迭代後,被刪除了,則lastRet重置爲-1 int lastRet = -1; public boolean hasNext() { return cursor != size(); //當前遊標值 等於 集合的size() 說明已經不能再迭代了。 } public E next() { int i = cursor; E next = get(i); lastRet = i; //lastRet 保存的是最近一次已經被迭代出去的元素索引 cursor = i + 1; //cursor爲立刻等待被迭代的元素的索引 return next; } public void remove() { if (lastRet < 0) //調用remove以前沒有調用next throw new IllegalStateException(); //則拋異常。這就是爲何在使用remove前,要next的緣由 OuterList.this.remove(lastRet); //從集合中刪除這個元素 if (lastRet < cursor) //集合刪除元素後,集合後面的元素的索引會都減少1,cursor也要同步後移 cursor--; lastRet = -1; //重置 } }

 

 

 

迭代出來的元素都是原來集合元素的拷貝blog

Java集合中保存的元素實質是對象的引用(能夠理解爲C中的指針),而非對象自己。

迭代出的元素也就都是 引用的拷貝,結果仍是引用。那麼,若是集合中保存的元素是可變類型的,咱們就能夠經過迭代出的元素修改原集合中的對象。

而對於不可變類型,如String  基本元素的包裝類型Integer 都是則不會反應到原集合中。

 

爲了便於理解,畫張圖:

 

         

 

 

 

驗證代碼:

 

public class Main
{

    public static void main(String[] args)
    {

        List<Person> li = new ArrayList<>();
        
        Person p = new Person("Tom");
        
        li.add(p);
        
        
        for(Person ap: li)
        {
            ap.setName("Jerry");
        }
        
        System.out.println(li.get(0).getName());     //Jerry  not Tom
        

    }

}


class Person
{
    
    public Person(String name)
    {
        this.name = (name==null?"":name);
        
    }
    
    private  String name;

    public String getName()
    {
        return name;
    }

    public void setName(String name)
    {
        if(name == null)
             name = "";
        this.name = name;
    }
    
}

 

 

 

 

小試牛刀,讓本身的類支持迭代。

public class Main
{

    public static void main(String[] args)
    {


        MyString s = new MyString("1234567");
        
        
        for(char c:s)
        {
            System.out.println(c);
        }

        

    }

}




class MyString implements Iterable<Character>
{
    
    private int length = 0;
    private String ineers = null;
    
    public MyString(String s)
    {
        this.ineers = s;
        this.length = s.length();
        
    }
    
    
    @Override
    public Iterator<Character> iterator()
    {
        
        
        class iter  implements Iterator<Character>     //方法內部類
        {
            private int cur= 0;
            
            
            @Override
            public boolean hasNext()
            {
                return cur != length;
            }

            @Override
            public Character next()
            {
                
                Character c = ineers.charAt(cur);
                cur++;
                return c;
            }
            
            public void remove()
            {
                 // do nothing 
                
            }

        }
        return new iter();     //安裝Iterable接口的約定,返回迭代器
                   
    }
    
}
相關文章
相關標籤/搜索