1. 程式人生 > >Java基礎面試題(18)----ArrayList集合原始碼解析

Java基礎面試題(18)----ArrayList集合原始碼解析

我們對ArrayList集合的原始碼進行解析,只是寫出了增刪改查的方法。

首先我們來看一下ArrayList的資料結構

  • 底層實際上是一個數組,在增加元素的時候,對陣列進行擴容,新增一個元素,容量增加1。
  • 實際儲存的是順序儲存的結構,每個位置的元素都有執行的索引,所以可以實現快速的查詢元素。 用簡單的圖片展示,如下: 在這裡插入圖片描述
  • 但是當在指定位置新增元素的時候,後面位置的元素統一向後移動,效率較低,這裡會呼叫系統的複製陣列的方法,因為無法看到原始碼,所以內有辦法深入研研究,這段程式碼如下:
  • 移除元素的圖片展示如下 在這裡插入圖片描述
 //複製陣列
System.arraycopy(elementData, index+1, elementData, index,  numMoved);

那我們簡單的看一下ArrayList的內部程式碼實現

package com.mainshi.mylist;

import java.io.Serializable;
import java.util.AbstractList;
import java.util.Arrays;
import java.util.List;
import java.util.RandomAccess;

public class MyArrayList<E> extends AbstractList implements List,RandomAccess,Cloneable,Serializable{


    //首先定義成員變數
    //靜態常量值,UID
    private static final long serialVersionUID = 8683452581122892189L;

    //預設容量
    private static final int DEFAULT_CAPACITY = 10;

    //空的元素資料
    private static final Object[] EMPTY_ELEMENTDATA = {};

    //
    private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};

    //非序列化物件陣列
    transient Object[] elementData;

    //長度
    private int size;

    //構造方法

    public MyArrayList() {
        this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
    }

    public MyArrayList(int initialCapacity){
        //做輸入引數的合法判斷
        if (initialCapacity > 0) {
            this.elementData = new Object[initialCapacity];
        } else if (initialCapacity == 0) {
            this.elementData = EMPTY_ELEMENTDATA;
        } else {
            throw new IllegalArgumentException("Illegal Capacity: "+
                    initialCapacity);
        }
    }


    @Override//獲取數值的方法
    public Object get(int index) {
        if(index>=size){
            throw new IndexOutOfBoundsException();
        }
        return elementData[index];
    }


    //獲取長度
    @Override
    public int size() {
        return size;
    }

    //新增的方法

    @Override
    public boolean add(Object o) {

       //擴容的方法
        ensureCapacityInternal(size + 1);
        //將新的元素賦值給最末尾的長度
        elementData[size++]=o;
        return true;
    }
    //擴容的方法
    private void ensureCapacityInternal(int minCapacity) {
        //三元運算子,如果現在的集合大小不等於預設的長度(建構函式有確認),最小擴容為0,
        //如果相等,最小擴容為10
       int minExpand=(elementData != DEFAULTCAPACITY_EMPTY_ELEMENTDATA)?0:DEFAULT_CAPACITY;
       //輸入的長度大於擴容的長度
       if (minCapacity>minExpand){
           ensureExplicitCapacity(minCapacity);
       }

    }

    private void ensureExplicitCapacity(int minCapacity) {
        modCount++;
        if (minCapacity-elementData.length>0){
             grow(minCapacity);
        }
    }

    //常見一個新的陣列,長度比之前的陣列加1;
    private void grow(int minCapacity) {
        // overflow-conscious code
        int oldCapacity = elementData.length;
        int newCapacity = oldCapacity + (oldCapacity >> 1);
        if (newCapacity - minCapacity < 0)
            newCapacity = minCapacity;
        // minCapacity is usually close to size, so this is a win:
        elementData = Arrays.copyOf(elementData, newCapacity);
    }




    //在指定的索引位置新增元素
    public  void add(int index,Object obj){

        //資料合法性檢查
        rangCheck(index);
        //擴容
        ensureCapacityInternal(size + 1);
        //賦值陣列
        System.arraycopy(elementData, index, elementData, index + 1,
                size - index);
        //將元素裝到對應位置
        elementData[index] = obj;
        //集合長度增加
        size++;
    }

    private void rangCheck(int index) {
        if (index>size || index<0){
            throw new IndexOutOfBoundsException("指定元素的位置"+index+"超出集合的長度");
        }
    }


    //移除指定位置的元素的方法

    public E remove(int index){
       //合法性檢查
        rangCheck(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; // clear to let GC do its work
        //將移除的元素返回
        return oldValue;
    }

    //提取元素的方法
    E elementData(int index) {
        return (E) elementData[index];
    }



    //移除指定的物件
    public boolean remove(Object object){
        if (object==null){//如果執行物件為null
            for (int index=0;index<size;index++){
                if(elementData(index)==null){
                    fastRemove(index);
                    return true;
                }
            }
        }else{//如果指定物件部位null
            for (int index=0;index<size;index++){
                if(elementData(index).equals(object)){
                    fastRemove(index);
                    return true;
                }
        }


    }

    return false;
}

    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
    }



    //修改元素的放法
    public Object set(int index,Object object){
        //範圍檢查
        rangCheck(index);
        //取出舊元素
       Object oldValue = elementData(index);
        //指定位置放入新的元素
        elementData[index]=object;
        //返回舊的元素
        return oldValue;

    }
 }