1. 為什么需要ArrayList?
記得在剛剛學習JAVA的時候,我們首先是學習了數組,這是我們學到的第一個可以存儲多個對象的實例或者基本類型的具體值,數組存儲的特點如下:
1.只能存儲同種類型的數據。
2.在定義數組時,必須指定該數組的大小,并且在不改變數組的前提下,不可修改其長度。
以上特性就會導致很多弊端。比如:我們往往不希望數組只能存儲一種數據,而是希望存儲我們想要存儲的數據,最好是在想要存儲的時候根據數據的類型指定存儲的類型。其次,我們也不想一開始就指定好數據的長度,而是希望這個數組的容量可以隨著我的數據的多少的改變而改變。
基于以上的弊端,Java中出現了集合。這是一種新的容器可以用來存儲數據,而集合的存儲方式有多種,常見的有鏈式存儲(LinkedList)和順序存儲(ArrayList)。
鏈式存儲底層是用一個個節點(Node)鏈接而成的,每個節點都存儲著一個對象值和下一個節點的位置(或上一個節點的位置)。
順序存儲底層是用一個數組存儲數據的,對于數組的弊端,順序存儲集合底層使用了ensureCapacity這個方法不斷擴容,ensureCapacity這個單詞字面翻譯是 保證能力。顧名思義,由于底層是一個數組,當我們存入一個對象時,我們需要保證數組是有空余位置的,因此在添加元素的時候,Java源碼會先經過這個方法進行判斷底層數組是否滿了,若滿了則會擴容數組(上面提到數組是不能直接擴容的,這里實際上是重新創建了一個更大空間的數組并把元素“搬運”過去)。這樣就解決了數組的一個弊端。而對于另一個弊端,Java則是巧妙的運用了泛型。泛型的內容非常繁多,這里結合實例希望大家可以更好地理解。
想象一下現在有一個需求,需要你實現一個的多值加法,但傳入的參數的類型是不確定的,可以有Integer,String,Double等等。這時候如果你用的是數組作為參數,那么那你肯定會想,最粗糙的方法是分別寫多個加法方法,對應不同的類型,但很明顯,代碼可讀性極差,那如果使用Object數組,然后再根據數據類型,轉換為對應的類型再計算?這樣也存在弊端!你根本不知道需要轉換為什么類型才合適。因此,針對這種情況,使用泛型集合是最合適的,我們只需要在傳入參數的時候使用泛型類型,而因為不同類型計算的過程是一致的,因此結果并沒有差別,也不會導致報錯。
2. ArrayList底層是如何實現的?
簡單介紹了ArrayList的用途以及和數組的區別,那么根據上面的講解,你應該大致了解它的實現原理了吧!
先不看源碼,如果你有一些數據結構與算法的基礎的話,你應該可以馬上得出下面結論:先在ArrayList類定義一個數組,接著定義一個添加,一個刪除,一個查詢,一個修改方法。實際上是對數組的操作,那么,刪除和添加可能需要移動大量的元素,這些都是在源碼中實現,但對應到效率也會很低,其次還需要一個擴容數組的方法。
如果你能想到上面這些,恭喜你,你已經掌握得很不錯。事實上,ArrayList的源碼確實包含以上方法,只不過還需要加上迭代器以及構造方法等。迭代器的出現是為了適應增強for語句(后面會細說),構造方法是為了初始化集合。
3. 結合源碼分析主要成員變量
ArrayList繼承AbstractList這個抽象類和List接口
List接口繼承Collection接口(實際上集合還有map集合等)
而Collection則是繼承了Iterable(可迭代的),Collection中包含了集合中通用的方法,包括增刪改查,只不過都未實現。而Iterable則是只有一個forEach方法,提供迭代。
接著我們回到ArrayList類,這是底層維護的數組,實際上對象存儲的地方
記錄集合的長度
返回集合的長度
判斷集合是否為空
根據索引獲取元素
添加元素
添加元素到指定位置
刪除元素
內部類的next方法實現迭代功能(我們平時使用增強for語句的判斷條件就是根據判斷是否有next值來實現的)
4. 個人的一點總結
Java的設計者很巧妙的設計了Java中的每個功能,很多時候,我們會覺得說我手動實現簡單的集合不需要這么復雜的代碼呀?甚至有些功能都不需要單獨作為一個方法。但這就是Java的魅力啊!
以前剛學代碼的我們,把代碼全都丟到main方法里面,我們會覺得提取出來是多么復雜,但當我們知道功能是有區別的,我們才知道這樣子做的用處。
曾經有個老師這么對我說,他說你知道為什么我們要費盡心思去設計各種類之間的關系,接口,抽象類,泛型等等嗎?那時候的我一臉茫然,他對我說,打個比方,你見過賣水果的店里還賣手機的嗎?我聽完后恍然大悟,對于一個小城鎮,確實可能存在一個小店賣著各種雜七雜八的東西,但一個千萬人口的大城市,是做不到的,這是格局啊!各種功能,各種設施都應該井井有條,關系明確。面向對象也好,設計模式也好,一切的功能都是為了大型程序做準備,這也是為什么Java一直可以大型應用的后端程序語言之一。