隨筆-13  評論-22  文章-0  trackbacks-0

          ArrayList

          本文github地址

          總體介紹

          ArrayList實現了List接口,是順序容器,即元素存放的數據與放進去的順序相同,允許放入null元素,底層通過數組實現。除該類未實現同步外,其余跟Vector大致相同。每個ArrayList都有一個容量(capacity),表示底層數組的實際大小,容器內存儲元素的個數不能多于當前容量。當向容器中添加元素時,如果容量不足,容器會自動增大底層數組的大小。前面已經提過,Java泛型只是編譯器提供的語法糖,所以這里的數組是一個Object數組,以便能夠容納任何類型的對象。

          ArrayList_base

          size(), isEmpty(), get(), set()方法均能在常數時間內完成,add()方法的時間開銷跟插入位置有關,addAll()方法的時間開銷跟添加元素的個數成正比。其余方法大都是線性時間。

          為追求效率,ArrayList沒有實現同步(synchronized),如果需要多個線程并發訪問,用戶可以手動同步,也可使用Vector替代。

          方法剖析

          set()

          既然底層是一個數組ArrayListset()方法也就變得非常簡單,直接對數組的指定位置賦值即可。

          public E set(int index, E element) {
              rangeCheck(index);//下標越界檢查
              E oldValue = elementData(index);
              elementData[index] = element;//賦值到指定位置,復制的僅僅是引用
              return oldValue;
          }

          get()

          get()方法同樣很簡單,唯一要注意的是由于底層數組是Object[],得到元素后需要進行類型轉換。

          public E get(int index) {
              rangeCheck(index);
              return (E) elementData[index];//注意類型轉換
          }

          add()

          跟C++ 的vector不同,ArrayList沒有bush_back()方法,對應的方法是add(E e)ArrayList也沒有insert()方法,對應的方法是add(int index, E e)。這兩個方法都是向容器中添加新元素,這可能會導致capacity不足,因此在添加元素之前,都需要進行剩余空間檢查,如果需要則自動擴容。擴容操作最終是通過grow()方法完成的。

          private void grow(int minCapacity) {
              int oldCapacity = elementData.length;
              int newCapacity = oldCapacity + (oldCapacity >> 1);//原來的1.5倍
              if (newCapacity - minCapacity < 0)
                  newCapacity = minCapacity;
              if (newCapacity - MAX_ARRAY_SIZE > 0)
                  newCapacity = hugeCapacity(minCapacity);
              elementData = Arrays.copyOf(elementData, newCapacity);//擴展空間并復制
          }

          由于Java GC自動管理了內存,這里也就不需要考慮源數組釋放的問題。

          ArrayList_grow

          空間的問題解決后,插入過程就顯得非常簡單。

          ArrayList_add

          add(int index, E e)需要先對元素進行移動,然后完成插入操作,也就意味著該方法有著線性的時間復雜度。

          addAll()

          addAll()方法能夠一次添加多個元素,根據位置不同也有兩個把本,一個是在末尾添加的addAll(Collection<? extends E> c)方法,一個是從指定位置開始插入的addAll(int index, Collection<? extends E> c)方法。跟add()方法類似,在插入之前也需要進行空間檢查,如果需要則自動擴容;如果從指定位置插入,也會存在移動元素的情況。
          addAll()的時間復雜度不僅跟插入元素的多少有關,也跟插入的位置相關。

          remove()

          remove()方法也有兩個版本,一個是remove(int index)刪除指定位置的元素,另一個是remove(Object o)刪除第一個滿足o.equals(elementData[index])的元素。刪除操作是add()操作的逆過程,需要將刪除點之后的元素向前移動一個位置。需要注意的是為了讓GC起作用,必須顯式的為最后一個位置賦null值。

          public E remove(int index) {
              rangeCheck(index);
              modCount++;
              E oldValue = elementData(index);
              int numMoved = size - index - 1;
              if (numMoved > 0)
                  System.arraycopy(elementData, index+1, elementData, index, numMoved);
              elementData[--size] = null//清除該位置的引用,讓GC起作用
              return oldValue;
          }

          關于Java GC這里需要特別說明一下,有了垃圾收集器并不意味著一定不會有內存泄漏。對象能否被GC的依據是是否還有引用指向它,上面代碼中如果不手動賦null值,除非對應的位置被其他元素覆蓋,否則原來的對象就一直不會被回收。

          posted on 2016-04-22 08:39 CarpenterLee 閱讀(1353) 評論(7)  編輯  收藏

          評論:
          # re: Java ArrayList源碼剖析[未登錄] 2016-04-22 10:05 | linda
          java源碼 高難度啊  回復  更多評論
            
          # re: Java ArrayList源碼剖析 2016-04-22 11:32 | kexue
          分析很清楚,請問博主插圖使用的是什么軟件繪制的?  回復  更多評論
            
          # re: Java ArrayList源碼剖析 2016-04-22 12:30 | CarpenterLee
          @kexue
          我用的是一款叫做Dia (software)的繪圖軟件,類似于MS visio,挺好用的。這里有它的介紹https://en.wikipedia.org/wiki/Dia_(software)。  回復  更多評論
            
          # re: Java ArrayList源碼剖析 2016-04-22 12:36 | CarpenterLee
          @linda
          Java代碼寫得比較清晰,還有注釋,看起來不是很費勁的。  回復  更多評論
            
          # re: Java ArrayList源碼剖析 2016-05-11 19:51 | 陳軍
          這邊博文有價值  回復  更多評論
            
          # re: Java ArrayList源碼剖析 2016-05-11 22:11 | CarpenterLee
          @陳軍
          常來轉轉,希望能給大家帶來些收獲。  回復  更多評論
            
          # re: Java ArrayList源碼剖析 2016-05-12 16:54 | www.niuchui.com
          學習了,感覺要消化一下。  回復  更多評論
            

          只有注冊用戶登錄后才能發表評論。


          網站導航:
           
          主站蜘蛛池模板: 德令哈市| 绥芬河市| 即墨市| 河曲县| 五家渠市| 洪江市| 宜川县| 故城县| 延吉市| 普兰县| 公主岭市| 陈巴尔虎旗| 工布江达县| 托里县| 嘉义县| 青海省| 太白县| 从江县| 凯里市| 三门县| 买车| 子洲县| 浮梁县| 汪清县| 察雅县| 鸡西市| 湛江市| 延吉市| 舞钢市| 武功县| 抚顺县| 鹰潭市| 昆明市| 馆陶县| 内江市| 延安市| 安多县| 简阳市| 辽宁省| 忻州市| 兴城市|