package com.example.demo.test;
 
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
 
/**
 * <p>
 * <code>ArrayListTest</code>
 * </p>
 * Description: JDK 1.8 普通集合类
 * {@link java.util.ArrayList} 底层其实就是一个Object[]
 *
 * @author Jalen
 * @date 2019/8/26 9:40
 */
public class ArrayListTest {
 
    /**
     * Test method
     * @param args arguments
     */
    public static void main(String[] args) {
        createArrayList();
    }
 
    /**
     * @see java.util.ArrayList#ArrayList() 创建一个空的list,底层其实是一个空的对象数组(final Object[] elementData = {})
     * @see java.util.ArrayList#add 添加元素。计算容量,设置容量,赋值
     *  {@link java.util.ArrayList#ensureCapacityInternal(int)}  minCapacity=size + 1, size default is 0
     *      {@link java.util.ArrayList#calculateCapacity(Object[], int)}  elementData legth is 0, minCapacity is 1
     *      {@link java.lang.Math#max(int, int)} if elementData legth is 0,then default is 10,compare with minCapacity, choose the bigger one as capacity
     *  {@link java.util.ArrayList#ensureExplicitCapacity(int)} modCount++(iterator operation), if elementData length(0) lower than minCapacity(10),then grow
     *      {@link java.util.ArrayList#grow(int)} oldCapacity is 0, newCapacity = minCapacity is 10
     *      {@link java.util.Arrays#copyOf(Object[], int)} set 10 length array obj copy as new elementData
     *      elementData[0] = "";  add value what you want
     * @see java.util.ArrayList#ArrayList(int) elementData = new Object[initialCapacity]
     */
    private static void createArrayList(){
        ArrayList<String> list = new ArrayList<>();
        list.add(generateRandomString());
        System.out.println(list.toString());
 
        ArrayList<String> newList = new ArrayList<>(5);
        newList.add(generateRandomString());  //默认5个长度的空数组(elementData length是5),当前需添加一个长度(minCapacity是1),直接赋值
        System.out.println(newList.toString());
 
        ArrayList<String> newerList = new ArrayList<>(5);
        System.out.println("size: " + newerList.size());
        newerList.add(generateRandomString());
        System.out.println("size: " + newerList.size());
        newerList.add(generateRandomString());
        newerList.add(generateRandomString());
        newerList.add(generateRandomString());
        newerList.add(generateRandomString());
        newerList.add(generateRandomString());  // 当添加第6个元素时,计算capacity不足,触发grow扩容,扩容到7
        newerList.add(generateRandomString());
        newerList.add(generateRandomString());  // 当添加第8个元素时,计算capacity不足,触发grow扩容,扩容到10
        newerList.add(generateRandomString());
        newerList.add(generateRandomString());
        newerList.add(generateRandomString());  // 当添加第11个元素时,计算capacity不足,触发grow扩容,扩容到15
        newerList.add(generateRandomString());
        newerList.add(generateRandomString());
        newerList.add(generateRandomString());
        System.out.println("size: " + newerList.size());  // 扩容公式为:oldCapacity + oldCapacity >> 1 = newCapacity
        System.out.println(newerList.toString());
 
        ArrayList<String> arrayList = new ArrayList<>(20);
        arrayList.add(generateRandomString());
        arrayList.add(generateRandomString());
        arrayList.add(generateRandomString());
        arrayList.add(generateRandomString());
        arrayList.add(generateRandomString());
        arrayList.add(generateRandomString());
        arrayList.add(generateRandomString());
        arrayList.add(generateRandomString());
        arrayList.add(generateRandomString());
        arrayList.add(generateRandomString());
        arrayList.add(generateRandomString());
        arrayList.add(generateRandomString());
        System.out.println(arrayList.toString());  // 减少扩容次数
 
        //插入操作,会引发扩容,且包含数组越界检测
        ArrayList<String> firstList = new ArrayList<>(5);
        firstList.add(generateRandomString());
        firstList.add(generateRandomString());
        firstList.add(generateRandomString());
        firstList.add(generateRandomString());
        firstList.add(2, "China");  //rangeCheckForAdd->ensureCapacityInternal->System.arraycopy
        firstList.add(4, "America"); //rangeCheckForAdd->ensureCapacityInternal(grow)->System.arraycopy
        System.out.println(firstList.toString()); //超出容量,必先扩容,然后讲当前list第二位向后移动,空出第二位,再给第二位赋值
 
        //修改操作,不存在扩容,但包含数据越界检测
        ArrayList<String> secondList = new ArrayList<>(5);
        secondList.add(generateRandomString());
        secondList.add(generateRandomString());
        secondList.add(generateRandomString());
        secondList.add(generateRandomString());
        secondList.set(2, "China"); //rangeCheck->get oldValue(index为2的旧值)->set newValue to "China"->return oldValue
        //secondList.set(4, "America"); //index=4, listSize=4, index>=listSize, throw exception
        System.out.println(secondList.toString());
 
        //根据下标截取subList
        ArrayList<String> thirdList = new ArrayList<>(5);
        thirdList.add("China");
        thirdList.add("America");
        thirdList.add("Russia");
        thirdList.add("England");
        thirdList.add("France");
        List<String> subThirdList = thirdList.subList(3, 5); //subListRangeCheck->SubList
        System.out.println(subThirdList.toString());
    }
 
    /**
     * 生成6个字节长度的随机字符串
     * @return 字符串
     */
    private static String generateRandomString() {
        char[] ch = new char[6];
        for (int i = 0; i < 6; i++) {
            Random rnd = new Random();
            int d = rnd.nextInt(26) + 97;
            char c = (char) d;
            ch[i] = c;
        }
        return new String(ch);
    }
}

扩容公式:

    /**
     * Increases the capacity to ensure that it can hold at least the
     * number of elements specified by the minimum capacity argument.
     *
     * @param minCapacity the desired minimum capacity
     */
    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);
    }