一家之言 姑妄言之 絮絮叨叨 不足爲訓
ListIterator接口註釋翻譯:
列表的迭代器,它允許程序員以任意方向遍歷列表,在迭代期間修改列表,並獲取迭代器在列表中的當前位置。ListIterator沒有當前元素。它的遊標位置總是位於調用previous()返回的元素和調用next()返回的元素之間。長度爲n的列表的迭代器有n+1個可能的光標位置,如下面的插入符號(^)所示:
Element(0) | Element(1) | Element(2) | Element(3) | … | Element(n-1) | |||||
---|---|---|---|---|---|---|---|---|---|---|
^ | ^ | ^ | ^ | ^ |
注意,remove和set(object)方法不是根據遊標位置定義的。它們被定義爲對調用next()或previous()返回的最後一個元素進行操作。
該接口是Java集合框架的成員。
筆者廢話:
這個接口的註釋說的我也是雲裏霧裏,但是我們大概可以從中略窺一二。首先它說明了我們這個接口是可以從任意方向遍歷的。如果你仔細看過這個接口內的方法聲明,也就明白了這個“任意方向”的含義。通俗來說,它有了所謂的“前驅節點”和“後繼節點”。
我相信看到這兩個名詞你可能就明白了這個接口的本意,它就是一個雙向鏈表,不過我們平常也叫它雙鏈表。
其次,它也告訴我們這個接口的遊標是不指向元素的,它位於前驅節點和後繼節點之間。不過我還是要說,前驅節點和後繼節點之間不是本身還有元素嗎?我實在不理解這個作者在寫這段註釋的含義。但是不可否認的是,它確實沒有當前元素。這個還是通過聲明的方法就可以得出的結論。
ListIterator接口信息:
public interface ListIterator<E> extends Iterator<E>
我們可以清楚的看到,ListIterator
是一個接口,而且這裏還規定了泛型機制。同時,這個接口繼承了Iterator
接口,關於Iterator
接口的解析請參照Iterator源碼逐條解析這篇文章吧。
ListIterator接口方法信息:
/**
* 如果此列表迭代器在正向遍歷列表時包含更多元素,則返回true。
* (換句話說,如果next將返回一個元素而不是拋出一個異常,則返回true。)
*
* @return 如果在正向遍歷列表時,列表迭代器有更多的元素則返回true
*/
boolean hasNext();
這裏覆寫了Iterator
接口中的hasNext()
方法。從註釋上來說它更多地描述了一個正向遍歷的概念,當然,這是因爲我們這個接口還有反向遍歷的方法hasPrevious()
。其餘的解釋和Iterator源碼逐條解析裏說的一樣,不過我還是複製到下面供參考。不過如果已經閱讀了我提到的這篇Iterator源碼逐條解析文章,那麼下面兩段忽略即可。
這個方法意在詢問當前遍歷的容器中是否含有下一個元素。這裏會涉及到一個指針操作,當然,我們java宣稱的可是沒有指針,所以,這我們可以把它稱之爲“指向”。一般來說,如果我們使用了某個集合的ListIterator
對象後,會在這個集合的上方出現一個空值,而我們的ListIterator
對象就指向這個空值。
但是需要注意的是,這個方法僅僅是詢問下一個元素是否存在,此時並不移動指向位置,只有調用了next()
方法後,這個指向位置纔會進行移動,即,移動到下一項。
/**
* 返回列表中的下一個元素並向前移動光標位置。可以重複調用此方法來
* 遍歷列表,也可以將此方法與對previous的調用混合在一起來回調用。
* (注意,交替調用next和previous將重複返回相同的元素。)
*
* @return the next element in the list
* @throws NoSuchElementException if the iteration has no next element
*/
E next();
這裏覆寫了Iterator
接口中的next()
方法。我們從註釋上可以看到,這個方法可以和previous()
方法重複使用。不過這裏也說明了如果交替使用的話將返回相同的元素。這個倒是容易理解,你遍歷前又遍歷後,便利後又遍歷前,一直魔力轉圈圈。那麼以下兩段依舊引自Iterator源碼逐條解析中的解析。如無疑問,那麼就跳過。
這個方法是與hasNext()
方法遙相呼應的。它代表着返回迭代器中的下一個元素。一般來說,我們都會通過hasNext()
方法來判斷是否有下一個元素,一旦有,那麼就調用next()
方法展示(取出)這個元素。
重複上面的一段話:調用了next()
方法後,容器的指向位置會進行移動,即,移動到下一項。
/**
* 如果該列表迭代器在反向遍歷列表時包含更多元素,則返回true。
* (換句話說,如果previous返回一個元素而不是拋出一個異常,則返回true。)
*
* @return 當以反向遍歷列表時,如果列表迭代器有更多的元素則返回true
*/
boolean hasPrevious();
好的,這個是我們ListIterator
接口定義的一個新方法。它和hasNext()
方法是對應的。一個是正向遍歷(hasNext()
),一個是反向遍歷(hasPrevious()
)。
這個方法意在詢問當前遍歷的容器中是否含有上一個元素。它依舊會存有一個指向元素的指向。不過它和hasNext()
方法一樣,僅僅是詢問上一個元素是否存在,此時並不移動指向位置,只有調用了previous()
方法後,這個指向位置纔會進行移動,即,移動到上一項。
/**
* 返回列表中的前一個元素,並將光標向後移動。可以反覆調用此方法以
* 向後遍歷列表,也可以將此方法與對next的調用混合在一起來回調用。
* (注意,交替調用next和previous將重複返回相同的元素。)
*
* @return 返回列表中的前一個元素
* @throws 如果迭代沒有先前的元素則拋出NoSuchElementException異常
*/
E previous();
這個是我們ListIterator
接口定義的一個新方法。我們從註釋上可以看到,這個方法可以和next()
方法重複使用。不過,需要注意的是,註釋中在解釋這個方法的時候使用了backwards
,即向後遍歷。其實就是我們通常意義上的向前遍歷(向左移動)。這裏不是翻譯的問題,而是理解性的問題。那麼以下兩段仿照Iterator源碼逐條解析中的解析。如無疑問,那麼就跳過。
這個方法是與hasPrevious()
方法遙相呼應的。它代表着返回迭代器中的上一個元素。一般來說,我們都會通過hasPrevious()
方法來判斷是否有上一個元素,一旦有,那麼就調用previous()
方法展示(取出)這個元素。
重複上面的一段話:調用了previous()
方法後,容器的指向位置會進行移動,即,移動到上一項。
/**
* 返回將由後續調用next返回的元素的索引。(如果列表迭代器位於列表的末尾,
* 則返回列表大小。)
*
* @return 對next的後續調用將返回的元素的索引,或者如果列表迭代器位於
* 列表末尾,則爲列表大小
*/
int nextIndex();
這個是我們ListIterator
接口定義的一個新方法。這個方法在註釋中說是“返回將由後續調用next返回的元素的索引”,實際上它返回當前元素的遊標,也就是當前元素的索引值(這個元素可還沒遍歷過哦)。通俗來說,當我們獲取到需要遍歷集合的ListIterator
時,這個時候我們的遊標cursor
肯定指向了0
。那麼這個nextIndex()
返回的就是0
。記住,這裏返回的,可是未遍歷過得元素索引,因爲我們的例子中並沒有提到調用next()
後再調用nextIndex()
。
/**
* 返回將由後續調用previous返回的元素的索引。(如果列表迭代器位於列表的開頭,
* 則返回-1。)
*
* @return 對previous後續調用將返回的元素的索引,如果列表迭代器位於
* 列表開頭,則爲-1
*/
int previousIndex();
這個方法的解釋其實和nextIndex()
相似,因爲其功能相反。它返回的就是當前元素遊標的前一項。可能有些許繞。也就是說,它返回的是我們當前最近一次遍歷過的元素的索引值。也就是這個方法的使用,起碼在第一次獲取到ListIterator
時,必須先進行next()
行爲,使得我們的遊標cursor
由0
變爲1
,然後再調用previousIndex()
方法才能返回0
這個索引,否則則返回-1
。
/**
* 從列表中刪除next或previous返回的最後一個元素(可選操作)。此調用
* 在每次調用next或previous時只能執行一次。只有在最後一次調用next
* 或previous之後沒有調用add時,纔可以執行此操作。
*
* @throws 如果此列表迭代器不支持刪除操作則拋出
* UnsupportedOperationException異常
* @throws 如果沒有調用next或previous,或者在最後一次調用next或
* previous之後調用了remove或add則拋出IllegalStateException異常
*/
void remove();
這個remove()
方法挺有意思。
首先,這個方法只有在調用了next()
或者previous()
方法之後纔可調用。而且你中途還不能調用add(E e)
操作。這個不難理解,一般我們在調用了next()
或者previous()
方法之後遊標進行變動。而刪除的就是跟這個遊標cursor
相關的所在位置的元素。當然,我們這裏也不確定是哪一個,因爲這畢竟是個接口說明,還未到實現本接口的具體實現。所以這裏我們只能進行猜測。
不過通過這種亦步亦趨的操作屬性,我們也能得出這裏最好不要進行添加行爲。因爲你可能破壞了當前的數據結構,造成刪除錯誤的結果。
其次,當我們沒有調用next()
方法或previous()
方法的話,或者最後一次調用next()
方法或previous()
方法之後調用了remove()
方法或add(E e)
方法會拋出IllegalStateException
異常。關於這個解釋我感覺還是看相關實現類的實現要好。因爲前半句易理解,如果你不調用next()
方法或previous()
方法的話,遊標不移動它都不知道刪誰。但後半句卻不是那麼容易理解。所以,我們還是看具體方法的實現吧(放心,這個可不是一個小小接口說明就能搞清楚的~)。
/**
* 將next或previous返回的最後一個元素替換爲指定的元素(可選操作)。
* 只有在最後一次調用next或previous之後既不調用remove也不調用add,
* 纔可以執行此調用。
*
* @param e 用來替換next或previous返回的最後一個元素的元素
* @throws 如果此列表迭代器不支持set操作則拋出
* UnsupportedOperationException異常
* @throws 如果指定元素的類阻止將其添加到此列表中則拋出
* ClassCastException異常
* @throws 如果指定元素的某些方面阻止將其添加到此列表中則拋出
* IllegalArgumentException異常
* @throws 如果沒有調用next或previous,或者在最後一次調用next
* 或previous之後調用了remove或add則拋出IllegalStateException異常
*/
void set(E e);
這個方法的註釋讓我百思不得其解,但是這個set(E e)
方法的本意我們還是可以大致弄清楚的,就是當你調用了next()
方法或者previous()
方法之後,如果你用了本方法,那麼就會修改當時你獲取的這個元素的值。譬如我們有一個數組:[“a” , “b” , “c” , “d”]。
當我們初始化拿到Iterator
的時候,開始使用next()
方法,這個時候返回的原始應該是"a"吧?對,然後你再調用set("c")
。這個時候你的數組就變成了:[“c” , “b” , “c” , “d”]。同理,調用previous()
也是這種情形。
具體的,我們還是看其實現類是如何進行操作的。
/**
* 將指定的元素插入列表(可選操作)。元素被插入到next將返回的元素之前(如果有的話),
* 以及previous將返回的元素之後(如果有的話)。(如果列表不包含元素,則新元素將成爲
* 列表中惟一的元素。)新元素被插入到隱式遊標之前:對next的後續調用不受影響,而對
* previous的後續調用將返回新元素。(這個調用將增加一個調用nextIndex或
* previousIndex返回的值。)
*
* @param e 要插入的元素
* @throws 如果此列表迭代器不支持add方法則拋出
* UnsupportedOperationException異常
* @throws 如果指定元素的類阻止將其添加到此列表中則拋出
* ClassCastException異常
* @throws 如果此元素的某些方面阻止將其添加到此列表中則拋出
* IllegalArgumentException異常
*/
void add(E e);
這個方法與其說是“添加”,我覺得不如說是“插入”來的更貼切些。
它本意是要在調用了next()
方法之後進行插入。抑或是在調用了previous()
方法之後進行插入。放心,你沒有看錯。都是在之後,在哪個之後呢?在你調用了next()
方法或previous()
方法返回的元素之後。
我們拿next()
方法舉例:
首先我們有一個容器(不一定是數組):
1 | 2 | 3 | 4 | 5 |
---|
當我們兩次調用next()
方法之後,你所返回的元素應該是下面^
所指向的那個:
1 | 2 | 3 | 4 | 5 | 6 |
---|---|---|---|---|---|
^ |
這個時候你開始利用add(E e)
方法進行插入,比如add(10)
。它會插入到哪裏呢?它會插入下面這個地方:
1 | 2 | 3 | 4 | 5 | |
---|---|---|---|---|---|
^ |
最後你得到的結果是這樣的:
1 | 2 | 10 | 3 | 4 | 5 |
---|---|---|---|---|---|
^ |
我們再拿previous()
方法舉例:
首先我們有一個容器(不一定是數組):
1 | 2 | 3 | 4 | 5 |
---|
當我們三次調用next()
方法之後緊接着調用一次previous()
方法。你所返回的元素應該是下面^
所指向的那個:
1 | 2 | 3 | 4 | 5 | 6 |
---|---|---|---|---|---|
^ |
這個時候你開始利用add(E e)
方法進行插入,比如add(10)
。它會插入到哪裏呢?它會插入下面這個地方:
1 | 2 | 3 | 4 | 5 | |
---|---|---|---|---|---|
^ |
最後你得到的結果是這樣的:
1 | 2 | 10 | 3 | 4 | 5 |
---|---|---|---|---|---|
^ |
你會發現,這個方法無論在哪個場景下使用,都會添加到返回元素的後面。但是並不代表註釋翻譯的不正確,它儘量的描述類使用該方法的區別。只不過我們是從現象上來確認這種情況。
OK,這些具體的實現方法我會在其具體的實現類裏面具體做介紹,這裏還是不摻雜那麼多的解釋或舉例。僅僅留給這個ListIterator
接口一個說一是一的解析吧。
至此,我們ListIterator
到此全部解析完畢(ಥ_ಥ)。