JDK1.8集合框架源码分析一-------------ArrayList

0.ArrayList特点:

       0.1)查询效率高:在其内部有下标,即有索引,直接就可以取到数据

       0.2) 删除慢:因为需要将当前后面的数据往前移动移位,这时会用到数据扩容技术,这样效率非常低

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 数组越界检查,即指定位置是否越界 (index允许的范围是 [0,size]

    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 数组越界检查 (index允许的范围是 [0,size)

    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 {

    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 implements RogerList {

    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 rogerArrayList = new RogerArrayList();
        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 rogerArrayList = new RogerArrayList(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 rogerArrayList = new RogerArrayList(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 rogerArrayList = new RogerArrayList(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));
        }
    }
}

 

你可能感兴趣的:(Java)