Basic review of javase (1) Deep parsing of ArrayList source code (JDK 1.8.0_92)

Keywords: Java JDK Attribute Unity

One of the problems we need to pay attention to when learning this piece of content is that the reference of the object is still stored in the collection, not the object itself.

The List interface extends Collection and declares the properties of the class set that stores a series of elements. Using a zero-based subscript, elements can be inserted and accessed through their positions in the list. A list can contain duplicate elements. List is a relatively important knowledge in the collection and is also the most commonly used in development.

We all know that ArrayList is implemented by arrays, but there is a big difference between ArrayList and ArrayList. As elements are added to ArrayList, the capacity of ArrayList increases automatically, and the capacity of ArrayList will not change after the array is declared. It's very important to find out exactly how it works. It's very rewarding to look at the source code (JDK 1.8.0_92) again today, so we can record and share it here.

1. Attributes in the Arraylist class

 1 public class ArrayList<E> extends AbstractList<E>
 2         implements List<E>, RandomAccess, Cloneable, java.io.Serializable
 3 {
 4     private static final long serialVersionUID = 8683452581122892189L;
 5 
 6     /**
 7      *Default initial capacity
 8      */
 9     private static final int DEFAULT_CAPACITY = 10;
10 
11     /**
12      *Shared empty array instances used for empty instances
13      */
14     private static final Object[] EMPTY_ELEMENTDATA = {};
15 
16     /**
17      * Object[]An array of types that stores the elements added to the ArrayList. The capacity of the ArrayList is the length of the Object [] type array
18      * When the first element is added, elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA in any empty ArrayList will be added
19      * Extended to DEFAULT_CAPACITY (default capacity).
20      */
21     private transient Object[] elementData;
22 
23     /**
24      * ArrayList Size (actually the value returned by the size() method)
25      *
26      * @serial
27      */
28     private int size;
29 
30 ......
31 
32 }
Class attribute

There are several points to be noted here:

The variable DEFAULT_CAPACITY refers to the default capacity of ArrayList. In fact, an Arraylist has just been initialized and its capacity is 0. When one is added, the capacity becomes 10, which is not handled when jdk1.6 is released. Next we will introduce them one by one.

The variable elementData is an array, which is used to cache the data in ArrayList (the data refers to the reference of the object) in the notes to the source code of JDK 1.8.0_92. The size of the ArrayList depends on the length of the cache array. It is also pointed out that the cache array is an empty array when initialized. The length of the cache array will be extended to the above DEFAULT_CAPACITY, which is 10.

The variable size refers to the size of the cache array, which is the length of the ArrayList.

2. Construction Method

 1 //When Constructing Method Parameters with Parameters ArrayList Initial length
 2 public ArrayList(int initialCapacity) {
 3         super();
 4         if (initialCapacity < 0)
 5             throw new IllegalArgumentException("Illegal Capacity: "+
 6                                                initialCapacity);
 7         this.elementData = new Object[initialCapacity];
 8     }
 9 //The construction method without parameters (the length of initialization is 0) is also our most commonly used construction method.
10 public ArrayList() {
11         super();
12         this.elementData = EMPTY_ELEMENTDATA;
13     }
14 //Constructing a method with parameters to construct a containing specified collection A list of elements that follow this collection The sequence returned by the iterator of
15 public ArrayList(Collection<? extends E> c) {
16         elementData = c.toArray();
17         size = elementData.length;
18         // c.toArray might (incorrectly) not return Object[] (see 6260652)
19         if (elementData.getClass() != Object[].class)
20             elementData = Arrays.copyOf(elementData, size, Object[].class);
21     }

It should be noted here that the implementation mechanism here is slightly different in different versions of jdk. As follows:

The construction method without parameters in jdk1.8.0_45:

1 public ArrayList() {
2   this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;  //DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {}
3 }

In JDK 1.6, the construction method without parameters is as follows:

1 public ArrayList() {    
2     this(10);  //public ArrayList(int initialCapacity)in this.elementData = new Object[initialCapacity];
3 }

The code in JDK 1.8.0_92 and jdk1.8.0_45 is slightly different, but their implementation mechanism is the same. They all start by declaring that an empty array expands its length to 10 when it is added, and JDK 1.6 declares an array whose length is 10 when it is declared. This is also slowly optimizing it.

When is the length of the array expanded? Let's see below.

3. Adding Elements

 1     //The element to be specified(E e)Add to the end of this list
 2     public boolean add(E e) {
 3         ensureCapacityInternal(size + 1);  // Increments modCount!!
 4         elementData[size++] = e;
 5         return true;
 6     }
 7 
 8     //The element to be specified(E e)Location of insertion into list(index)
 9     public void add(int index, E element) {
10         rangeCheckForAdd(index); //Judgement parameter index Whether or not? IndexOutOfBoundsException
11 
12         ensureCapacityInternal(size + 1);  // Increments modCount!!  If the array length is insufficient, it will be expanded
13         System.arraycopy(elementData, index, elementData, index + 1,
14                          size - index); //From the source array index After the beginning of the position size-index Unity of individual elements and move back one bit
15         elementData[index] = element;
16         size++;
17     }
18 
19     /**
20      * Adds all elements in the collection to the end of the list in the order of elements returned by the iterator for the specified collection
21      * @throws NullPointerException if the specified collection is null
22      */
23     public boolean addAll(Collection<? extends E> c) {
24         Object[] a = c.toArray();
25         int numNew = a.length;
26         ensureCapacityInternal(size + numNew);  // Increments modCount
27         //Array a[0,...,numNew-1]Copy to arrays elementData[size,...,size+numNew-1]
28         System.arraycopy(a, 0, elementData, size, numNew); 
29         size += numNew;
30         return numNew != 0;
31     }
32 
33     /**
34      * Starting at the specified location, insert all elements in the specified collection into this list in the order of the elements returned by the iterator of the specified collection
35      * @throws IndexOutOfBoundsException {@inheritDoc}
36      * @throws NullPointerException if the specified collection is null
37      */
38     public boolean addAll(int index, Collection<? extends E> c) {
39         rangeCheckForAdd(index); //Judgement parameter index Whether or not? IndexOutOfBoundsException
40 
41         Object[] a = c.toArray();
42         int numNew = a.length;
43         ensureCapacityInternal(size + numNew);  // Increments modCount
44 
45         int numMoved = size - index;
46         if (numMoved > 0)
47             //Array first elementData[index,...,index+numMoved-1]Copy to elementData[index+numMoved,...,index+2*numMoved-1]
48             //That is, from the source array index After the beginning of the position numMoved Unified backward movement of individual elements numNew position
49             System.arraycopy(elementData, index, elementData, index + numNew,
50                              numMoved);
51         //Array again a[0,...,numNew-1]Copy to arrays elementData[index,...,index+numNew-1]
52         System.arraycopy(a, 0, elementData, index, numNew);
53         size += numNew;
54         return numNew != 0;
55     }

The specific implementation of the above additions is not listed above, but I'll put them below.

Specific implementation methods:

 1      /**
 2      * public Method to enable users to manually set the capacity of ArrayList
 3      * @param   minCapacity Expected minimum capacity
 4      */
 5     public void ensureCapacity(int minCapacity) {
 6         int minExpand = (elementData != DEFAULTCAPACITY_EMPTY_ELEMENTDATA)
 7             // any size if not default element table
 8             ? 0
 9             // larger than default for default empty table. It's already
10             // supposed to be at default size.
11             : DEFAULT_CAPACITY;
12 
13         if (minCapacity > minExpand) {
14             ensureExplicitCapacity(minCapacity);
15         }
16     }
17 
18     private void ensureCapacityInternal(int minCapacity) {
19         //When elementData For space time, ArrayList The minimum initial capacity is DEFAULT_CAPACITY(10)
20         if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
21             minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
22         }
23         ensureExplicitCapacity(minCapacity);
24     }
25 
26     private void ensureExplicitCapacity(int minCapacity) {
27         modCount++;
28         // overflow-conscious code
29         if (minCapacity - elementData.length > 0)
30             grow(minCapacity);
31     }
32 
33     //The maximum capacity that an array can be allocated; when the required array size exceeds VM Limitations may lead to OutOfMemoryError
34     private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
35 
36     /**
37      * Increase the capacity of the array to ensure that it can accommodate at least the specified minimum number of elements
38      * @param minCapacity Expected minimum capacity
39      */
40     private void grow(int minCapacity) {
41         // overflow-conscious code
42         int oldCapacity = elementData.length;
43         //Note the expansion here capacity The way is to move it one bit to the right and add the original number, which is actually an extension of 1..5 times
44         int newCapacity = oldCapacity + (oldCapacity >> 1);
45         if (newCapacity - minCapacity < 0)
46             newCapacity = minCapacity;
47         if (newCapacity - MAX_ARRAY_SIZE > 0) 
48             newCapacity = hugeCapacity(minCapacity); //Set the maximum allocatable capacity of an array
49         // minCapacity is usually close to size, so this is a win:
50         elementData = Arrays.copyOf(elementData, newCapacity);
51     }
52 
53     private static int hugeCapacity(int minCapacity) {
54         if (minCapacity < 0) // overflow
55             throw new OutOfMemoryError();
56         return (minCapacity > MAX_ARRAY_SIZE) ?
57             Integer.MAX_VALUE :
58             MAX_ARRAY_SIZE;
59     }

It is worth noting here that the > operator in the growth () method is actually equivalent to dividing by 2. For example:

 1010 decimal system: 10 original number
 10100 decimal system: 20 left shift one digit number = number << 1;
 1010 decimal system: 10 right shift one digit number = number > > 1;

So if we follow up the add (E) method, we will know that when we add ArrayList, we enter the add() method at the beginning and then execute the ensureCapacityInternal() method, where elementData = EMPTY_ELEMENTDATA is true, so minCapacity = 10. Then minCapacity - elementData. length > 0 is true and the growth () method is executed. Every time the growth () method is executed, a new array is generated and the length is 1.5 times that of the original array. This is the basic principle of automatic capacity expansion of ArrayList.

I've seen how jdk1.6 works here before, slightly different but also generates new arrays 1.5 times the length of the original array. As for why it is 1.5 times that I think it may be that Daniel got such an optimal solution with his own experience or scientific deduction. I don't know. Guess is welcome to add.

There are many ways to delete elements, modify elements and find elements in ArrayList, which are easy to read and understand. They are not written here.

It's easier to understand the basic principles of ArrayList and then think about the characteristics of ArrayList. Compared with LinkedList, ArrayList is more suitable for search operations and LinkedList is more suitable for insertion or deletion operations. Because ArrayList is implemented by arrays, and the data stored in memory is continuous, it is easy to locate one element to another. LinkedList is different from LinkedList. LinkedList is implemented by double-linked lists. It has to look for elements one by one, but LinkedList has a high efficiency in performing intermediate insertion or deletion operations.

Also in eclipse to view the source code is more commonly used shortcut keys Alt + left and right direction keys, can be achieved in the previous mouse cursor jump is very practical.

Welcome to fill in the gaps!

Posted by webpals on Sat, 30 Mar 2019 21:03:28 -0700