【金三銀四】ArrayList圖解存儲原理與數據結構揭祕

前言:

你好,早上、中午、下午、晚上好。我是辛巴哥。一名無緣985,平常996工程師。 java

在這裏插入圖片描述
今天我辛巴哥來教娜娜學ArrayList

開始快速

import java.util.ArrayList;
/**** * 求關注 微信搜:Java大型網站架構 */
public class ArrayListDemo {


    public static void main(String[] args) {
       ArrayList<String> arrayList= new ArrayList<String>();
       arrayList.add("辛巴");
       arrayList.add("娜娜");
       arrayList.add("微信搜:Java大型網站架構");
       for (String s:arrayList){
           System.out.println(s);
       }
    }
}
複製代碼

在這裏插入圖片描述

你們在平常開發的中咱們是這樣去使用的,只要是java開發人員,不管你是1年工做仍是10年工做。我相信Arraylist都是很是熟悉使用的。對我說的是熟悉使用,可是知道其底層實現的人就少不少了,這發生在我身邊的事情,小編我如今在某大廠上班,常常面試一些工做5-6年的程序員,問問他們hashmap和arraylist底層實現,都知道是數組、鏈表、hash算法,可是細問下就露餡了,因此今天有必要和你們分享下arraylist底層實現。固然hashmap的底層實現我也講過,能夠看我以前的文章。程序員

技術本質

不少老鐵都知道arraylist底層是用數組爲存儲結構的。咱們先來熟悉下數組面試

數組算法

數組:採用一段連續的存儲單元來存儲數據。對於指定下標的查找,時間複雜度爲O(1);對於通常的插入刪除操做, 涉及到數組元素的移動,其平均複雜度也爲O(n)數組

在這裏插入圖片描述

Java代碼表示bash

//數組:採用一段連續的存儲單元來存儲數據。
   //特色:指定下標O(1) 刪除插入O(N) 數組:查詢快 插入慢 ArrayList
   public static void main(String[] args) {
      Integer[] integers = new Integer[10];
      integers[0]=1;
      integers[1]=2;
      integers[2]=3;
      integers[9]=4;
複製代碼

插入原理

咱們熟悉了數組的特性以後,咱們在回到剛纔咱們快速入門的代碼 ,咱們add三個字符串是怎麼插入到咱們數組裏面去的了, 是怎麼插(吃啊插)入進去的了?咱們來看下源碼:微信

​ arrayList.add("辛巴"); ​ arrayList.add("娜娜"); ​ arrayList.add("微信搜:Java大型網站架構"); 架構

在這裏插入圖片描述

在這裏插入圖片描述

經過上述代碼咱們能夠肯定泛型e插入到elementData數組裏 而且size++。ensureCapacityInternal方法咱們先放放等會說。網站

咱們先說下說怎麼插入到數組中,從0開始按順序size++插入到數組中分別爲:ui

在這裏插入圖片描述
若是有一天插入的數據不數組長度還多了怎麼辦?

擴容

剛纔在add方法有ensureCapacityInternal方法還沒說,這個方法咱們來看下源碼。

private void ensureCapacityInternal(int minCapacity) {
        ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
    }

private static int calculateCapacity(Object[] elementData, int minCapacity) {
        if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
            return Math.max(DEFAULT_CAPACITY, minCapacity);
        }
        return minCapacity;
    }
複製代碼

源碼意思:計算最小容量,DEFAULTCAPACITY_EMPTY_ELEMENTDATA(默認容量)是DEFAULTCAPACITY_EMPTY_ELEMENTDATA=10

算出最小容量在看下:

private void ensureExplicitCapacity(int minCapacity) {
        modCount++;
        // overflow-conscious code
        if (minCapacity - elementData.length > 0)
            grow(minCapacity);
    }
複製代碼

傳入最小容量值,修改+1。 minCapacity - elementData.length > 0判斷須要的容量與默認容量的大小,差爲負值是不須要擴容的。若是大於0說正數就須要擴容調用grow方法

private void grow(int minCapacity) {
        // overflow-conscious code
        int oldCapacity = elementData.length;
        int newCapacity = oldCapacity + (oldCapacity >> 1);
        if (newCapacity - minCapacity < 0)
            newCapacity = minCapacity;
        if (newCapacity - MAX_ARRAY_SIZE > 0)
            newCapacity = hugeCapacity(minCapacity);
        // minCapacity is usually close to size, so this is a win:
        elementData = Arrays.copyOf(elementData, newCapacity);
    }
複製代碼

源碼意思:數組擴容 第一個if條件是: 首先把數組的長度賦給老的容量,也就是10,而後新的容量newCapacity=老的容量(10)+老的容量右移一位(5), 第二個if條件是: 若是新容量-(size+1)爲負數,把size+1賦給新容量。若是新容量比數組的最大擴容量都大,會報異常,或者把最大的賦給它。若是都不是,就把新容量拷貝給數組,擴容完成。 對應圖以下:

在這裏插入圖片描述

刪除原理

咱們知道add插入的原理,刪除其實也不難了吧。大體意思就是經過下表找到數組對應的對象讓其爲null,可是咱們以前插入時擴容的數組怎麼處理了?咱們如今不須要這麼多數據了呀?

下標位置刪除:

public E remove(int index) {
        rangeCheck(index);//檢查index這個值是否有在size裏面,保證其正確合法性
        modCount++;
        E oldValue = elementData(index);
        int numMoved = size - index - 1;/ /將index+1以及以後的元素向前移動一位,覆蓋被刪除的值
        if (numMoved > 0)
            System.arraycopy(elementData, index+1, elementData, index,
                             numMoved);
        elementData[--size] = null; // 該對應下表值賦值爲null。

        return oldValue;
    }
複製代碼

在這裏插入圖片描述
在這裏插入圖片描述
對象元素刪除: 指定元素刪除:首先判斷是否爲空,空的時候直接刪除

public boolean remove(Object o) {   
 //判斷元素是否爲空
 if (o == null) {   
     for (int index = 0; index < size; index++)    
         if (elementData[index] == null) { 
             fastRemove(index);      
             return true;    
         }   
 } else {     
     for (int index = 0; index < size; index++)   
         if (o.equals(elementData[index])) {  
             fastRemove(index);      
             return true;       
         }   
 }  
 //若是沒有匹配元素,返回false
 return false;
}
複製代碼

快速刪除:不須要檢測index,直接刪除

private void fastRemove(int index) {   
modCount++;   
int numMoved = size - index - 1;  
if (numMoved > 0)    
   System.arraycopy(elementData, index+1, elementData, index,numMoved);          elementData[--size] = null; // clear to let GC do its work
}
複製代碼

在這裏插入圖片描述

總結:

如今知道爲何數組:插入刪除慢,查詢快(這個下篇文章證實) 由於插入有可能須要庫容。 由於刪除須要從新分配數組中數據元素。好比圖中刪除「娜娜」 娜娜下標爲1,凡是在下標爲1以後的元素都須要往前挪一個位置, 這是件很可怕的事情。由於刪除的元素越靠前,那就意味着須要挪動的數據就越多。所以數組插入和刪除會變慢的緣由在於此了明白的牛人點個贊或者回復下吧。

好了各位,以上就是這篇文章的所有內容了,能看到這裏的人呀,都是牛人。 白嫖很差,創做不易,各位的支持和承認,就是我創做的最大動力,咱們下篇文章見!

相關文章
相關標籤/搜索