偷偷摘套内射激情视频,久久精品99国产国产精,中文字幕无线乱码人妻,中文在线中文a,性爽19p

迭代器筆試題,居然難倒很多人

開發(fā) 前端
有位小朋友最近正在為年后換工作做準(zhǔn)備,但是遇到一個問題,覺得很不可思議的一道筆試題。然后我把這道題發(fā)到技術(shù)群里,發(fā)現(xiàn)很多人居然不知道,很多都是連蒙帶猜的說。感覺很有必要寫一篇文章來說道說道。

[[379497]]

有位小朋友最近正在為年后換工作做準(zhǔn)備,但是遇到一個問題,覺得很不可思議的一道筆試題。然后我把這道題發(fā)到技術(shù)群里,發(fā)現(xiàn)很多人居然不知道,很多都是連蒙帶猜的說。感覺很有必要寫一篇文章來說道說道。

奇怪的筆試題閱讀下面這段代碼,請寫出這段代碼的輸出內(nèi)容:

  1. import java.util.ArrayList; 
  2. import java.util.Iterator; 
  3. import java.util.*; 
  4.  
  5. public class Test { 
  6.     public static void main(String[] args) { 
  7.  
  8.         List<String> list = new ArrayList<>(); 
  9.         list.add("1"); 
  10.         list.add("2"); 
  11.         list.add("3"); 
  12.         Iterator iterator = list.iterator(); 
  13.         while (iterator.hasNext()) { 
  14.             String str = (String) iterator.next(); 
  15.             if (str.equals("2")) { 
  16.                 iterator.remove(); 
  17.             } 
  18.         } 
  19.         while (iterator.hasNext()) { 
  20.             System.out.println(iterator.next()); 
  21.         } 
  22.         System.out.println("4"); 
  23.     } 

他寫出來的答案是:

奇怪的是,你把這道題目發(fā)給你身邊人,讓他們回答這道面試題輸出結(jié)果是什么,說這個結(jié)果的人非常多。不行你試試。

 

答案明顯不對,因為在第一個while里的 iterator.hasNext()==false后才會到第二個while里來,同一個Iterator對象,前面調(diào)一次iterator.hasNext()==false,再判斷一次結(jié)果不還是一樣嗎?,

所以第二個while判斷為false,也就不會再去遍歷iterator了,由此可知本體答案是:4。

下面我們來分析一下為什么是具體底層是怎么實現(xiàn)的。

這里的Iterator是什么?

  • 迭代器是一種模式、詳細(xì)可見其設(shè)計模式,可以使得序列類型的數(shù)據(jù)結(jié)構(gòu)的遍歷行為與被遍歷的對象分離,即我們無需關(guān)心該序列的底層結(jié)構(gòu)是什么樣子的。只要拿到這個對象,使用迭代器就可以遍歷這個對象的內(nèi)部
  • Iterable 實現(xiàn)這個接口的集合對象支持迭代,是可以迭代的。實現(xiàn)了這個可以配合foreach使用~
  • Iterator 迭代器,提供迭代機制的對象,具體如何迭代是這個Iterator接口規(guī)范的。

Iterator說明

  1. public interface Iterator<E> {  
  2.     //每次next之前,先調(diào)用此方法探測是否迭代到終點 
  3.     boolean hasNext(); 
  4.     //返回當(dāng)前迭代元素 ,同時,迭代游標(biāo)后移 
  5.     E next();  
  6.     /*刪除最近一次已近迭代出出去的那個元素。 
  7.      只有當(dāng)next執(zhí)行完后,才能調(diào)用remove函數(shù)。 
  8.      比如你要刪除第一個元素,不能直接調(diào)用 remove()   而要先next一下( ); 
  9.      在沒有先調(diào)用next 就調(diào)用remove方法是會拋出異常的。 
  10.      這個和MySQL中的ResultSet很類似 
  11.     */ 
  12.     default void remove() { 
  13.         throw new UnsupportedOperationException("remove"); 
  14.     }  
  15.     default void forEachRemaining(Consumer<? super E> action) { 
  16.         Objects.requireNonNull(action); 
  17.         while (hasNext()) 
  18.             action.accept(next()); 
  19.     } 

這里的實現(xiàn)類是ArrayList的內(nèi)部類Itr。

  1. private class Itr implements Iterator<E> { 
  2.         int cursor;       // index of next element to return 
  3.         int lastRet = -1; // index of last element returned; -1 if no such 
  4.         //modCountshi ArrayList中的屬性,當(dāng)添加或刪除的時候moCount值會增加或者減少 
  5.         //這里主要是給fail-fast使用,避免一遍在遍歷,一遍正在修改導(dǎo)致數(shù)據(jù)出錯 
  6.         //此列表在結(jié)構(gòu)上被修改的次數(shù)。結(jié)構(gòu)修改是指改變結(jié)構(gòu)尺寸的修改列表, 
  7.         //或者以這樣的方式對其進行擾動,進步可能會產(chǎn)生錯誤的結(jié)果。 
  8.         int expectedModCount = modCount; 
  9.          
  10.         public boolean hasNext() { 
  11.             //cursor初始值為0,沒掉一次next方法就+1 
  12.             //size是ArrayList的大小 
  13.             return cursor != size
  14.         } 
  15.  
  16.         @SuppressWarnings("unchecked"
  17.         public E next() { 
  18.             checkForComodification(); 
  19.             int i = cursor
  20.             if (i >= size
  21.                 throw new NoSuchElementException(); 
  22.             //把ArrayList中的數(shù)組賦給elementData 
  23.             Object[] elementData = ArrayList.this.elementData; 
  24.             if (i >= elementData.length) 
  25.                 throw new ConcurrentModificationException(); 
  26.             //每調(diào)用一次next方法,游標(biāo)就加1 
  27.             //cursor=lastRet+1 
  28.             cursor = i + 1; 
  29.             //返回ArrayList中的元素 
  30.             return (E) elementData[lastRet = i]; 
  31.         } 
  32.  
  33.         public void remove() { 
  34.             if (lastRet < 0) 
  35.                 throw new IllegalStateException(); 
  36.             checkForComodification(); 
  37.  
  38.             try { 
  39.                 //調(diào)用ArrayList中remove方法,溢出該元素 
  40.                 ArrayList.this.remove(lastRet); 
  41.                 //cursor=lastRet+1, 
  42.                 //所以此時相當(dāng)于cursor=cursor-1 
  43.                 cursor = lastRet; 
  44.                 lastRet = -1; 
  45.                 expectedModCount = modCount; 
  46.             } catch (IndexOutOfBoundsException ex) { 
  47.                 throw new ConcurrentModificationException(); 
  48.             } 
  49.         } 
  50.         final void checkForComodification() { 
  51.             if (modCount != expectedModCount) 
  52.                 throw new ConcurrentModificationException(); 
  53.         } 

再回到上面題目中:

第一個iterator.hasNext()

  • 第1次循環(huán)hasNext方法中:cursor==0, size==3,所以cursor != size返回true。
  • next方法中:cursor=0+1。返回"1"。

第2次循環(huán)

  • hasNext方法中:cursor==1, size==3,所以cursor != size返回true。
  • next方法中:cursor=1+1。返回"2"。
  • remove方法中:cursor==cursor-1==2-1=1,把ArrayList中的"2"給刪除了,所以size==2。

第3次循環(huán)

  • hasNext方法中:cursor==1, size==2,那么cursor != size返回true。
  • next方法中:cursor=1+1==2;返回"3"。

第4次循環(huán)

  • hasNext方法中:cursor==2, size==2,那么cursor != size返回false。

第二個iterator.hasNext()

hasNext方法中:cursor==2, size==2,所以cursor != size返回false。

所以,最后只輸出"4",即答案為4.

Iterator與泛型搭配

  • Iterator對集合類中的任何一個實現(xiàn)類,都可以返回這樣一個Iterator對象??梢赃m用于任何一個類。
  • 因為集合類(List和Set等)可以裝入的對象的類型是不確定的,從集合中取出時都是Object類型,用時都需要進行強制轉(zhuǎn)化,這樣會很麻煩,用上泛型,就是提前告訴集合確定要裝入集合的類型,這樣就可以直接使用而不用顯示類型轉(zhuǎn)換.非常方便.

foreach和Iterator的關(guān)系

  • for each以用來處理集合中的每個元素而不用考慮集合定下標(biāo)。就是為了讓用Iterator簡單。但是刪除的時候,區(qū)別就是在remove,循環(huán)中調(diào)用集合remove會導(dǎo)致原集合變化導(dǎo)致錯誤,而應(yīng)該用迭代器的remove方法。

使用for循環(huán)還是迭代器Iterator對比

  • 采用ArrayList對隨機訪問比較快,而for循環(huán)中的get()方法,采用的即是隨機訪問的方法,因此在ArrayList里,for循環(huán)較快
  • 采用LinkedList則是順序訪問比較快,iterator中的next()方法,采用的即是順序訪問的方法,因此在LinkedList里,使用iterator較快
  • 從數(shù)據(jù)結(jié)構(gòu)角度分析,for循環(huán)適合訪問順序結(jié)構(gòu),可以根據(jù)下標(biāo)快速獲取指定元素.而Iterator 適合訪問鏈?zhǔn)浇Y(jié)構(gòu),因為迭代器是通過next()和Pre()來定位的.可以訪問沒有順序的集合.
  • 而使用 Iterator 的好處在于可以使用相同方式去遍歷集合中元素,而不用考慮集合類的內(nèi)部實現(xiàn)(只要它實現(xiàn)了 java.lang.Iterable 接口),如果使用 Iterator 來遍歷集合中元素,一旦不再使用 List 轉(zhuǎn)而使用 Set 來組織數(shù)據(jù),那遍歷元素的代碼不用做任何修改,如果使用 for 來遍歷,那所有遍歷此集合的算法都得做相應(yīng)調(diào)整,因為List有序,Set無序,結(jié)構(gòu)不同,他們的訪問算法也不一樣.(還是說明了一點遍歷和集合本身分離了)。

總結(jié)

  • 迭代出來的元素都是原來集合元素的拷貝。
  • Java集合中保存的元素實質(zhì)是對象的引用,而非對象本身。
  • 迭代出的對象也是引用的拷貝,結(jié)果還是引用。那么如果集合中保存的元素是可變類型的,那么可以通過迭代出的元素修改原集合中的對象。

本文轉(zhuǎn)載自微信公眾號「Java后端技術(shù)全?!?,可以通過以下二維碼關(guān)注。轉(zhuǎn)載本文請聯(lián)系Java后端技術(shù)全棧公眾號。

 

責(zé)任編輯:武曉燕 來源: Java后端技術(shù)全棧
相關(guān)推薦

2018-02-13 14:48:17

戴爾

2024-09-12 08:32:42

2022-01-05 23:34:02

顯示器濾藍光LED

2022-02-06 00:07:19

互聯(lián)網(wǎng)失業(yè)職業(yè)

2025-06-13 10:14:55

2019-08-21 08:24:34

技術(shù)過濾器代碼

2021-06-24 09:08:34

Java代碼泛型

2022-07-06 10:33:39

技術(shù)債務(wù)CIO

2017-12-13 15:57:12

2019-12-09 10:02:41

泛型ypeScript前端

2020-06-04 18:34:15

路由器耗電硬件

2021-01-15 05:39:13

HashMapHashTableTreeMap

2025-02-21 08:48:16

Typescript內(nèi)置聯(lián)合類型

2020-06-29 08:28:36

v-for 解構(gòu)函數(shù)

2014-05-09 15:29:21

2020-11-16 11:24:00

Spring AOP數(shù)據(jù)庫

2019-08-08 16:00:08

HTTPGETPOST

2021-09-21 10:33:56

人工智能科學(xué)技術(shù)

2020-06-08 19:16:52

大數(shù)據(jù)IT技術(shù)

2021-02-22 13:14:00

計算機編程技術(shù)
點贊
收藏

51CTO技術(shù)棧公眾號