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();

 

posted @ 2016-12-16 15:04  冰镇矿泉水  阅读(7008)  评论(0编辑  收藏  举报