1. 程式人生 > >JDK1.8集合框架原始碼分析一-------------ArrayList

JDK1.8集合框架原始碼分析一-------------ArrayList

1.ArrayList初始化

      1.1 無參建構函式,預設一個空陣列

      1.2 帶容量的有參建構函式:根據容量引數的值範圍來初始化

      1.3 原始碼中陣列預設的初始容量為 :10

      1.4 原始碼中陣列預設的最大容量為:Integer.MAX_VALUE - 8

2.ArrayList 新增元素

      2.1 陣列擴容

      2.2 新增元素

從下面的程式碼可以得出如果陣列的初始容量為1,那麼陣列擴容後的陣列容量為 2;

因為 陣列容量為1時,第一次新增元素時,不用擴容

當第二次新增時,才需要擴容,

這時 size = 1 ---> minCapacity = size + 1 = 2

                             oldeCapacity = 1

                             newCapacity  = 1 +

1 >> 1 = 1 + 0 = 1 

              所以: newCapacity - minCapacity = -1 < 0 ----> newCapacity = minCapacity = 2

//新增元素
public boolean add(Object e) {
        //陣列擴容
        ensureCapacityInternal(size + 1);

        elementData[size++] = e;

        return true;
} 
//陣列擴容
private void ensureCapacityInternal(int minCapacity) {
        //如果資料為空陣列
        // -即初始化的時候,使用的是無參建構函式
        //              或者使用的是0容量的有參建構函式
        // 從預設的陣列容量和傳遞的陣列最小容量中取較大的值
        if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
            minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
        }
        //如果當前陣列的容量大於需要新增元素所需的最小容量,則不需要擴容
        if(minCapacity < elementData.length){
            return;
        }
        //當前陣列的容量
        int oldCapacity = elementData.length;
        //擴容後的陣列容量=當前陣列的容量*1.5
        int newCapacity = oldCapacity + oldCapacity >> 1;
        //如果擴容後的容量比陣列最小容量小,
        // 則直接使用陣列的最小容量作為擴容後的陣列的容量
        if(newCapacity - minCapacity < 0){
            newCapacity = minCapacity;
        }
        //根據新的容量建立新的陣列
        //把當前陣列的資料拷貝到新的陣列中去
        elementData = Arrays.copyOf(elementData,newCapacity);
}

3.ArrayList指定位置新增元素

    3.1 陣列越界檢查,即指定位置是否越界

    3.2 陣列擴容

    3.3 新增元素

    public boolean add(int index, Object e) {
        rangeCheckForAdd(index);
        //陣列擴容
        ensureCapacityInternal(size + 1);
        // 0 1 2 3 4 --- size = 5
        // A B D E F --- 在D位置上插入C元素 index = 2
        // 需要把D E F 元素整體向後移動一位 變成 A B D D E F
        // 然後在把index=2 的位置替換成新的元素C即可
        // 則是直接在陣列的最後新增要給元素,無需移動陣列,直接新增元素
        if (index != size)
            System.arraycopy(elementData, index, elementData, index + 1, size - index);

        elementData[index] = e;
        size++;
        return true;
    }

    private void rangeCheckForAdd(int index) {
        if (index > size || index < 0) {
            throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
        }
    }

    private String outOfBoundsMsg(int index) {
        return "Index: " + index + ", Size: " + size;
    }

4.ArrayList 根據下表移除元素

    4.1 陣列越界檢查

    4.2 陣列移動

    4.3 陣列最後一個元素置空

    @Override
    public E remove(int index) {
        rangeCheck(index);

        E oldValue = (E) elementData[index];

        fastRemove(index);

        return oldValue;
    }

    private void rangeCheck(int index) {
        if (index >= size)
            throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
    }

    private void fastRemove(int index) {
        //A B C D E 如果index = 2 即移除 C元素
        //只需把 D E 整體向前移動一位,A B D E E
        // 然後把最後一位置空即可 A B D E null
        // step1 算出移動元素的個數
        int numMov = size - index - 1;
        // step2 如果移動的元素個數大於0,則移動陣列
        //       如果移動的元素等於0,則說明刪除的元素是最後一個元素,直接置空即可
        if (numMov > 0)
            System.arraycopy(elementData, index + 1, elementData, index, numMov);
        elementData[--size] = null;
    }

5.ArrayList 指定元素刪除

    5.1 找出陣列中第一個滿足指定元素的下標 也就是說jdkArrayList元素只能刪除首個滿足條件的資料,不能刪除所有滿足

條件的元素

   5.2 利用下標刪除元素

    @Override
    public boolean remove(Object obj){
        if(obj == 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(obj.equals(elementData[index])){
                    fastRemove(index);
                    return true;
                }
            }
        }

        return  false;
    }

6.自己手寫的ArrayList原始碼程式碼以及Junit測試類

package com.roger.collection;

public interface RogerList<E> {

    boolean add(E e);

    boolean add(int index, E e);

    E get(int index);

    int size();

    E remove(int index);

    boolean remove(Object obj);
}
package com.roger.collection.impl;

import com.roger.collection.RogerList;

import java.util.Arrays;

public class RogerArrayList<E> implements RogerList<E> {

    private final int DEFAULT_CAPACITY = 10;
    private final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
    private Object[] elementData;
    private int size;

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

    public RogerArrayList(int initialCapacity) {
        if (initialCapacity > 0) {
            this.elementData = new Object[initialCapacity];
        } else if (initialCapacity == 0) {
            this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
        } else {
            throw new IllegalArgumentException("Illegal Capacity:" + initialCapacity);
        }
    }

    @Override
    public boolean add(E e) {
        //陣列擴容
        ensureCapacityInternal(size + 1);

        elementData[size++] = e;

        return true;
    }

    @Override
    public boolean add(int index, E e) {
        rangeCheckForAdd(index);
        //陣列擴容
        ensureCapacityInternal(size + 1);
        // 0 1 2 3 4 --- size = 5
        // A B D E F --- 在D位置上插入C元素 index = 2
        // 需要把D E F 元素整體向後移動一位 變成 A B D D E F
        // 然後在把index=2 的位置替換成新的元素C即可
        //如果index == size
        // 則是直接在陣列的最後新增要給元素,無需移動陣列,直接新增元素
        if (index != size)
            System.arraycopy(elementData, index, elementData, index + 1, size - index);

        elementData[index] = e;
        size++;
        return true;
    }

    private void rangeCheckForAdd(int index) {
        if (index > size || index < 0) {
            throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
        }
    }

    private String outOfBoundsMsg(int index) {
        return "Index: " + index + ", Size: " + size;
    }

    private void ensureCapacityInternal(int minCapacity) {
        //如果資料為空陣列
        // -即初始化的時候,使用的是無參建構函式
        //              或者使用的是0容量的有參建構函式
        // 從預設的陣列容量和傳遞的陣列最小容量中取較大的值
        if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
            minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
        }
        //如果當前陣列的容量大於需要新增元素所需的最小容量,則不需要擴容
        if (minCapacity < elementData.length) {
            return;
        }
        //當前陣列的容量
        int oldCapacity = elementData.length;
        //擴容後的陣列容量=當前陣列的容量*1.5
        int newCapacity = oldCapacity + oldCapacity >> 1;
        //如果擴容後的容量比陣列最小容量小,
        // 則直接使用陣列的最小容量作為擴容後的陣列的容量
        if (newCapacity - minCapacity < 0) {
            newCapacity = minCapacity;
        }
        //根據新的容量建立新的陣列
        //把當前陣列的資料拷貝到新的陣列中去
        elementData = Arrays.copyOf(elementData, newCapacity);
    }

    @Override
    public E get(int index) {
        rangeCheck(index);
        return (E) elementData[index];
    }

    @Override
    public E remove(int index) {
        rangeCheck(index);

        E oldValue = (E) elementData[index];

        fastRemove(index);

        return oldValue;
    }

    private void rangeCheck(int index) {
        if (index >= size)
            throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
    }

    @Override
    public boolean remove(Object obj){
        if(obj == 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(obj.equals(elementData[index])){
                    fastRemove(index);
                    return true;
                }
            }
        }

        return  false;
    }

    private void fastRemove(int index) {
        //A B C D E 如果index = 2 即移除 C元素
        //只需把 D E 整體向前移動一位,A B D E E
        // 然後把最後一位置空即可 A B D E null
        // step1 算出移動元素的個數
        int numMov = size - index - 1;
        // step2 如果移動的元素個數大於0,則移動陣列
        //       如果移動的元素等於0,則說明刪除的元素是最後一個元素,直接置空即可
        if (numMov > 0)
            System.arraycopy(elementData, index+1, elementData, index, numMov);
        elementData[--size] = null;
    }

    @Override
    public int size() {
        return size;
    }
}
package com.roger.collection.impl;

import com.roger.collection.RogerList;
import org.junit.Test;

import static org.junit.Assert.*;

public class RogerArrayListTest {

    @Test
    public void testAdd() {

        RogerList<String> rogerArrayList = new RogerArrayList<String>();
        rogerArrayList.add("Roger");
        rogerArrayList.add("Mary");
        rogerArrayList.add("Bruce");
        for (int i = 0; i < rogerArrayList.size(); i++) {
            System.out.println(rogerArrayList.get(i));
        }

    }

    @Test
    public void testAddByPos() {
        RogerList<String> rogerArrayList = new RogerArrayList<String>(1);
        rogerArrayList.add("Roger");
        rogerArrayList.add("Mary");
        rogerArrayList.add("Bruce");
        rogerArrayList.add(1, "Andy");
        for (int i = 0; i < rogerArrayList.size(); i++) {
            System.out.println(rogerArrayList.get(i));
        }
    }

    @Test
    public void testRemove(){
        RogerList<String> rogerArrayList = new RogerArrayList<String>(1);
        rogerArrayList.add("Roger");
        rogerArrayList.add("Mary");
        rogerArrayList.add("Bruce");
        rogerArrayList.add(3, "Andy");


        rogerArrayList.remove(1);

        for (int i = 0; i < rogerArrayList.size(); i++) {
            System.out.println(rogerArrayList.get(i));
        }
    }

    @Test
    public void testRemoveByObj(){
        RogerList<String> rogerArrayList = new RogerArrayList<String>(1);
        rogerArrayList.add("Roger");
        rogerArrayList.add("Mary");
        rogerArrayList.add("Bruce");
        rogerArrayList.add(3, "Andy");


        rogerArrayList.remove("Andy");
        rogerArrayList.remove(null);
        for (int i = 0; i < rogerArrayList.size(); i++) {
            System.out.println(rogerArrayList.get(i));
        }
    }
}