iterator的實現原理


1.iterator遍歷linkedlist集合

Iterator li = list.iterator();
        while(li.hasNext()){
            System.out.println(li.next());
    }

這里可以看見Iterator li = list.iterator();

 public Iterator<E> iterator() {
        return new Itr();
    }

那么這個iterator()方法是在它的抽象父類中,通過new Itr();去實例化這個Iterator對象。

 public boolean hasNext() {
            return cursor != size();
        }

這里cursor初始化值為0;

當cursor等於size的時候,hasNext返回false;

 public E next() {
            checkForComodification();
            try {
                int i = cursor;
                E next = get(i);
                lastRet = i;
                cursor = i + 1;
                return next;
            } catch (IndexOutOfBoundsException e) {
                checkForComodification();
                throw new NoSuchElementException();
            }
        }

那么這里可以一個很關鍵的一點它使用的還是get方法。

 Node<E> node(int index) {
        // assert isElementIndex(index);

        if (index < (size >> 1)) {
            Node<E> x = first;
            for (int i = 0; i < index; i++)
                x = x.next;
            return x;
        } else {
            Node<E> x = last;
            for (int i = size - 1; i > index; i--)
                x = x.prev;
            return x;
        }
    }

那我們現在看看get()方法是怎么遍歷Node的無論無論這個index是多少?它都從first開始,或者last,取決於index < (size >> 1),這是個很巧妙的設計。看看index是不是超過size的一般,選擇從后first還是last,這時我們也可以找到鏈表結構查詢慢的根本原因,在於無論這個size有多大它都需要從first后last開始查詢。遠遠慢於使用索引的arraylist。

 

2.iterator遍歷ArrayList集合

 

 public E get(int index) {
        rangeCheck(index);

        return elementData(index);
    }

 

事實上iterator();是在Arraylist和linkedlist的共同抽象父類abstractList中,唯有get();實現不同,所以Arraylist查詢的速度要遠遠高於LinkedList.

 

2.iterator遍歷hushmap集合

add();
        Iterator<String> map = map.keySet().iterator();
        while(map.hasNext()){
            System.out.println(map.next());
    }

那么這里就是遍歷key一種方法,map.keySet().iterator();下面來看keyset()方法

 public Set<K> keySet() {
        Set<K> ks;
        return (ks = keySet) == null ? (keySet = new KeySet()) : ks;
    }

這里是通過keysett對象這里來看keySet類的iterator()方法

public final Iterator<K> iterator()     { return new KeyIterator(); }

這里就通過KeyIterator()方法實現了這個Iterator接口,這時候我們看KeyIterator()是如何重寫這個next()方法的。

public final K next() { return nextNode().key; }
    }

那么這里返回nextNode().key;現在來看nextNode()

 final Node<K,V> nextNode() {
            Node<K,V>[] t;
            Node<K,V> e = next;
            if (modCount != expectedModCount)
                throw new ConcurrentModificationException();
            if (e == null)
                throw new NoSuchElementException();
            if ((next = (current = e).next) == null && (t = table) != null) {
                do {} while (index < t.length && (next = t[index++]) == null);
            }
            return e;
        }

這里就是遍歷的核心內容,因為hashtable的關系,它的遍歷需要判斷table數組的鏈表中是否沒有數據,如果沒有數據而且table還沒有到最大值,這時候我們的table數組下標加以1,開始遍歷下一個數組,因為我們put一個對象時,它的存儲方式完全根據對象的hashcode來存儲的,本身它的取值是有順序的,但是存儲的時候是無序,所以取出來的數據也就沒有順序可言了。

map.values.iterator();

這里就很簡單了,nextnode.key變成nextnode.value;

網上有人說遍歷key和value的性能不一樣,不知道為什么,看到這里,我認為性能是沒有區別的。

關於hashSet的遍歷

參照map.keyset().iterator();

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM