The implementation principle and Vector of ArrayList

Keywords: less Java JDK

The core point of the underlying implementation of ArrayList

1. The collection bottom layer is implemented by using array
2. Why can a set store infinite size? ####The implementation of array expansion technology

Arrays.copyOf:
To copy the array, return the copied array. Parameters are the copied array and the copied length.
Return a new array. Expand the length of the original array to 2, and expand it to 10. The original data remains the same.

Code example implementation:

package com.mmall.demo2.demotest;

import java.util.Arrays;

public class Test001 {
    public static void main(String[] args) {
        Object[] objects = {1, 2};
        System.out.println("Original array length" + objects.length);
        // Return a new array. Expand the length of the original array to 2, and expand it to 10. The original data remains the same.
        Object[] objects2 = Arrays.copyOf(objects, 10);
        System.out.println("Length of new array" + objects2.length);

    }
}

Operation result:

System.arraycopy method:
If the array is relatively large, then using System.arraycopy will have advantages, because it uses memory replication, which saves a lot of time such as array addressing and access
Parameter explanation:
System.arraycopy(src,srcPos,dets,destPos, length);
src: source array;
srcPos: the starting position of the source array to be copied; - where to start copying from the original array. The subscript starts at 0.
dest: destination array;
destPos: the starting position where the destination array is placed; -- starting from where the destination array is placed. The subscript starts at 0.
Length: the length of the copy. --The length of the array to copy. Be careful not to cross the border when using.

Example code:

  int[] fun ={0,1,2,3,4,5,6};
//        src: source array;
//        srcPos: the starting position of the source array to be copied; -- where to start copying from the original array.
//        dest: destination array;
//        destPos: the starting position where the destination array is placed; -- starting from where the destination array is placed.
//        Length: the length of the copy. --Length of array to copy
        System.arraycopy(fun,0,fun,3,3);
        for (int i : fun) {
            System.out.print(i);
        }

The operation result is:

Error example code:

The length of the copy is 7: an array out of bounds error will be reported. Because its position starts from subscript 3, there are only four positions from the original array data of fun, position subscript 3 to the last subscript position. So the maximum length is 4.

Analyzing the source code of JDK1.8ArrayList collection

After jdk 1.7, the array default data size code is stored in the add method.
In jdk1.6, the default constructor initializes the elementData size.
Implementation of Arraylist based on array

  1. Construction method resolution.
    Default construction method:
//(in jdk1.6, the default constructor initializes the elementData size)
 //The constructor knows that jdk1.7 does not initialize the size in the constructor. 
private Object[] elementData; 
//Default constructor 
public ArrayList() { 
        this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
    }
      private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};

Construction method with parameters:

public ArrayList(int initialCapacity) {
        if (initialCapacity > 0) { //If the parameter is greater than 2, initialize the array and assign the array capacity
            this.elementData = new Object[initialCapacity];
        } else if (initialCapacity == 0) {
            this.elementData = EMPTY_ELEMENTDATA;
        } else { //Cannot be less than 0 otherwise an exception is thrown.
            throw new IllegalArgumentException("Illegal Capacity: "+
                                               initialCapacity);
        }
    }
  1. add(index) resolution:
    The default initialization size of the underlying array of Arraylist is 10 object arrays (jdk1.7 is initialized in the add method.)
  private static final int DEFAULT_CAPACITY = 10;

 public boolean add(E e) {
 		//size the actual arrayList length.
        ensureCapacityInternal(size + 1); 
        //Assign using Subscripts
        elementData[size++] = e;
        
        return true;
    }

Code resolution:
//Determine whether it is an empty array
//Compare the size, take the maximum value, default menu capacity default size 10, minCapacity is 1 for the first time

private void ensureCapacityInternal(int minCapacity) {
//Determine whether it is an empty array
 if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
 			//Compare the size, take the maximum value, default menu capacity default size 10, minCapacity is 1 for the first time
            minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
  }
        //Expand the capacity of the array.
        ensureExplicitCapacity(minCapacity);
}
private void ensureExplicitCapacity(int minCapacity) {
        modCount++;

        //Whether the actual existing capacity (10 by default) is greater than the length of elementData storage.
        if (minCapacity - elementData.length > 0)
            grow(minCapacity);
            
    }
    

If the length of the array is greater than the length of the current array after the element is added, the capacity will be expanded, and the length of the array will be increased by half of the original array. Each expansion is 1.5 times.
//Expand 1.5 times the original capacity, for example, the original capacity is 2, 2 + 2 / 2 = 3
int newCapacity = oldCapacity + (oldCapacity >> 1);

// Increase array space
	private void grow(int minCapacity) {
		// overflow-conscious code
	int oldCapacity = elementData.length;
	 // 1.5 times capacity expansion based on the original capacity
	int newCapacity = oldCapacity + (oldCapacity >> 1)
	//Judge whether it is less than minCapacity after 1.5 times of capacity expansion 
	if (newCapacity - minCapacity < 0)
	// Minimum guaranteed capacity is the same as minCapacity
		newCapacity = minCapacity; 
		
	if (newCapacity - MAX_ARRAY_SIZE > 0)
	 // Maximum capacity cannot be exceeded
		newCapacity = hugeCapacity(minCapacity);


	elementData = Arrays.copyOf(elementData, newCapacity);

get(index) resolution:

 public E get(int index) {
 		//Judge whether the index is greater than or equal to size (elementData.length) by exceeding the boundary
        rangeCheck(index);

        return elementData(index);
    }

Transboundary judgment

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

remove(index) analysis according to index:

Source code:

public E remove(int index) {
		//Cross boundary inspection
        rangeCheck(index);

        modCount++;
        //Get value from subscript
        E oldValue = elementData(index);
		//Calculate the length after the deleted element (size=elementData.length)
        int numMoved = size - index - 1;
        
        if (numMoved > 0)
        	//The following elements are overwritten one by one, starting with the deleted elements.
            System.arraycopy(elementData, index+1, elementData, index,numMoved);
            
         //Last element is null
        elementData[--size] = null; // clear to let GC do its work

        return oldValue;
    }

Example of removing arrayList values
Suppose subscript 2 is deleted and the content is the value of c

Array changes after deletion.

 //Last element is null
 elementData[--size] = null; // clear to let GC do its work

//Calculates the length after the deleted element.

//Calculate the length after the deleted element
  int numMoved = size - index - 1;

//The following elements are overwritten one by one, starting with the deleted elements.
index+1 start copy value start position
index is replaced from there
The length of the value to be copied by numMoved.

//The following elements are overwritten one by one, starting with the deleted elements.
 System.arraycopy(elementData, index+1, elementData, index,numMoved);

remove(obj) parsing based on objects:
Source code:

public boolean remove(Object o) {
        if (o == null) {
            for (int index = 0; index < size; index++)
                if (elementData[index] == null) {
                    fastRemove(index);
                    return true;
                }
        } else {
        	//Loop through, take out the value and compare.
            for (int index = 0; index < size; index++)
                if (o.equals(elementData[index])) {
                	//Delete by subscript
                    fastRemove(index);
                    return true;
                }
        }
        return false;
    }

Delete according to subscript (source code)

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
    }

It can be seen from the source code that the efficiency of deleting based on the value is the lowest, but if the same value exists, the first one will be deleted, and the second one will not be deleted.

add(index,obj) resolution:
Source code

public void add(int index, E element) {
		//1. Cross boundary judgment
        rangeCheckForAdd(index);
		//2.elementData capacity initialization and capacity expansion
        ensureCapacityInternal(size + 1);  // Increments modCount!!
        //
        System.arraycopy(elementData, index, elementData, index + 1, size - index);
        
        elementData[index] = element;
        
        size++;
    }

Implementation schematic diagram:
Process 1

Process 2

Process 2

//index start of subscript to insert,
//index + 1 starts from the element after the subscript value to be inserted,
//size - index length; the length of the element after the subscript to be inserted
 System.arraycopy(elementData, index, elementData, index + 1, size - index);

Vector bottom floor

Vector is thread safe, but its performance is lower than ArrayList.
The main differences between ArrayList and Vector are as follows:

(1) : Vector is thread safe. There are many synchronized in the source code, but ArrayList is not. As a result, Vector efficiency cannot be compared with ArrayList;

 public synchronized boolean add(E e) {
        modCount++;
        ensureCapacityHelper(elementCount + 1);
        elementData[elementCount++] = e;
        return true;
    }

(2) : both ArrayList and Vector use linear continuous storage space. When the storage space is insufficient, ArrayList will increase by default by 50% and Vector by 2 times;

Source code of Vector expansion:

  private void grow(int minCapacity) {
        // overflow-conscious code
        int oldCapacity = elementData.length;
        int newCapacity = oldCapacity + ((capacityIncrement > 0) ?
                                         capacityIncrement : oldCapacity);
        if (newCapacity - minCapacity < 0)
            newCapacity = minCapacity;
        if (newCapacity - MAX_ARRAY_SIZE > 0)
            newCapacity = hugeCapacity(minCapacity);
        elementData = Arrays.copyOf(elementData, newCapacity);
    }

capacityIncrement defaults to 0, the default constructor. Therefore, Vector is increased by default by 2 times;

(3) : Vector can set capacityIncrement, but ArrayList can't. literally, it is the parameter of capacity, Increment and capacity growth.

Published 23 original articles, praised 0, visited 185
Private letter follow

Posted by icyfire624 on Sat, 01 Feb 2020 23:25:32 -0800