public interface List<E> extends Collection<E>
public interface Collection<E> extends Iterable<E>
對於Iterable()接口,內部包含了iterator的獲取,和forech方法
public interface Iterable{
Iterator iterator();
void forech();
}
//Iterator接口
public interface Iterator{
boolean hasNext;
E next();
void remove();
···
}
複製代碼
Collection接口繼承了Iterable接口,而對於每一個數據結構,其內部的遍歷方式不一樣,因此具體的子類分別定義了本身的iteratornode
public Iterator<E> iterator() {
return new Itr();
}
private class Itr implements Iterator<E>
複製代碼
好比ArrayListz中Iterator的遍歷方式bash
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];
}
複製代碼
好比LinkedList中的遍歷方式數據結構
在LinkedList中並無實現Iterator接口,而是隻實現的ListIterator接口
對於ListIterator接口
public interface ListIterator extends Iterator{
//除了有iterator所包含的方法,還含有的其它特有方法
boolean hasPrevious();
E previous();
void set();
void add();
//也就是說ListIterator 支持修改,添加元素等操做,而且支持倒序遍歷
//咱們看它的一個子類
private class ListItr implements ListIterator<E> {
ListItr(int index) {
// assert isPositionIndex(index);
next = (index == size) ? null : node(index);
nextIndex = index;
}
//從它的構造方法中能夠看出,ListIterator還支持從指定位置遍歷
}
}
//因爲LinkedList中爲鏈表結構,因此遍歷方式有所不一樣
public E next() {
checkForComodification();
if (!hasNext())
throw new NoSuchElementException();
lastReturned = next;
next = next.next;
nextIndex++;
return lastReturned.item;
}
複製代碼
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();
}
}
咱們知道直接調用List的remove方法會產生錯誤,由於remove後,後面的元素會向前移動
而在Iterator的remove方法中,調用了List的remove方法後,iterator仍是將cursor=lastRet,實現了對remove
操做的封裝。
再看下邊一行代碼,lastRet=-1,又將lastRet賦值爲-1;因此,必須調用了next方法,指向下一個元素後,remove方法
纔會有效,否則會拋出IllegalStateException,因此Iterator的remove操做,必然在next操做以後調用。
複製代碼
衆多遍歷方式中爲何使用Iterator?
對於LinkedList,內部爲鏈表結構。對於下邊這種操做ui
LinkedList list = new LinkedList();
for(int i=0;i<list.size;i++){
list.get(i);
}
複製代碼
它的時間複雜度爲O(n^2),而若是使用iterator,它的時間複雜度爲O(n)
實際上爲了提升查找效率,linkedList中採用了簡單二分查找元素。this
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;
}
}
複製代碼
還有就是Iterator的設計思想,它把訪問邏輯從不一樣類型的集合類中抽象出來,從而避免向客戶端暴露集合的內部結構,不一樣的集合能夠在內部實現本身不一樣的遍歷操做。spa