1. 程式人生 > >Java原始碼系列(2):Iterable介面

Java原始碼系列(2):Iterable介面

對於以陣列形式儲存的多條資料,我們通常是用下表index來遍歷陣列,或進行相關操作,結構如下:

對於以連結串列形式儲存的多條資料,我們通常是用指標next來遍歷陣列,或進行相關操作,結構如下:

這主要是由他們的資料結構決定的,陣列是一塊連續的空間儲存,而連結串列則不是連續的空間。

接下來,是不是有人要問咦,這連結串列挺有順序的啊,這不整整齊齊排好了嗎?nonono,我只是為了版面好看故意排好的呢,

那真實的可能是這樣的:(* ̄︶ ̄)

說到這裡,那我們再來重溫一下陣列和連結串列各自的優缺點:

1.在查詢或修改方面:

  • 陣列因為是一段連續的空間,所以通過下標index查詢,比如我要查第三個元素就很快,直接陣列名[下標]就行。
  • 連結串列因為是不是連續的空間,所以要通過指標next來查詢,比如我要查第三個元素,得從開始,挨個往後面查。

2.在新增或刪除方面:

  • 陣列因為是一段連續的空間,所以我比如要往第三個元素後面加一個數據,就要先把第三個元素後面的那一個元素的空間挪出來,就是先把陣列長度加1,然後把第三個元素後面的資料挨個往後挪一個,然後再把要加的元素放在第三個元素後面的位置。
  • 連結串列因為不是一段連續的空間,所以我比如要往第三個元素後面加一個數據,只要將該資料的next賦值為第四個元素的位置,再將第三個元素的next賦值為該元素的位置。

那下面我們就來想一個問題,比如我原來是採用的陣列來儲存的1萬名員工資訊,對其進行新增,刪除工作,沒啥問題,然後專案中這員工達到了1000萬,明顯這新增,刪除就扛不住了,那我們就要改為連結串列的形式。但是問題就來了,比如我程式碼中有100個地方用到了迴圈的方式,如果這時候改,那就得改100個,這完全就是勞動力的浪費,加入100個尚能改,那1000個,10000個呢?噹噹噹,這篇文章的主角登場啦,那就是Iterable介面。

首先,我們得知道他是啥,他是一個Java提供給我們的一個介面,這個接口裡面有啥呢,當然是看原始碼啦。

public interface Iterable<T> {
    Iterator<T> iterator();
}
public interface Iterator<E> {
    boolean hasNext();

    E next();

    void remove();
}

Iterable裡面有一個iterator方法,該方法返回一個Iterator型別的資料,那Iterator裡面有三個方法,分別是hasNext(下面是否還有元素),next(下一個元素),remove(刪除剛剛遍歷過的元素)。

接下來,我們就來用用,畢竟這光看理論也是不行的,得先寫寫。

比如有一個數組,裡面的元素分別是1,3,2,4,6,需要輸出該陣列的元素。

public class Test {
  public static void main(String[] args) {
    //構造陣列
    List<Integer> list = new LinkedList<>();
    //構造連結串列
    //List<Integer> list = new ArrayList<>();
    list.add(1);
    list.add(3);
    list.add(2);
    list.add(4);
    list.add(6);
    //定義iterator
    Iterator iterator = list.iterator();
    //while迴圈
    while (iterator.hasNext()) {//判斷下面是否還有元素
      Integer number = (Integer) iterator.next();//指向下一個元素
      System.out.println(number);
    }
  }
}

執行結果如下:

這是Iterable最常見的用法,看程式碼中的有兩種資料的構建方式,而下面的輸出語句是一樣的,就說明使用Iterable來遍歷並不基於結構,那現在剛才提出的問題就可以解決了。就算專案在推進的過程臨時換結構,只要使用Iterable就可以解決。

當然我們並不能止步於此,下面我們來思考一下,剛才我們看原始碼的時候,是在Iterable中使用Iterator,然後Iterator介面中有三個方面,而我們在使用他的時候,也使用了hasNext和next方法,事實上,我們剛才使用的List是繼承了Collection介面,而Collection介面也繼承了Iterable介面,而Iterable介面繼承了Iterator介面,這樣我們就發現他是挨個繼承的關係,那既然我們在遍歷的時候主要的方法是hasNext和next方法,那是不是就可以不必多加一層繼承關係,直接讓Collection繼承於Iterator介面?

下面公佈答案,當然是不行的,因為Iterator介面中的三個方法hasNext,next,remove都是基於當前位置的,也就是如果沒有當前位置,hasNext是不知道下面有沒有資料的,next是不知道下面一個元素是什麼,remove是不知道將要刪除哪個元素的,現在當前位置是在Iterator介面的對應實現中。如果讓Collection直接繼承於Iterator,勢必導致集合中包含當前位置的資訊,如果此時是一個程序當然沒問題,但是如果是多個程序,他們對同一集合進行操作,那這些方法就都沒有意義。

我們假設有兩個程序對同一個集合進行操作,有個程序可能慢一點,有個程序可能快一點,他們之間相差兩個位置,那在查詢的時候,當前位置到底是聽哪個程序的?

終於到了最後,哈哈哈,我是不會讓你們開心的,來道題目練練

public class Test {
  public static void main(String[] args) {
    //構造陣列
    List<Integer> list = new LinkedList<>();
    list.add(1);
    list.add(3);
    list.add(2);
    //定義iterator
    Iterator iterator = list.iterator();
    //while迴圈
    while (iterator.hasNext()) {//判斷下面是否還有元素
      Integer number = (Integer) iterator.next();//指向下一個元素
      System.out.println(number);
            if(number==3){
                iterator.remove();
            }
     }
}

猜猜結果是啥