I. Introduction of ArrayList
ArrayList is a linear data structure whose bottom layer is implemented in an array, equivalent to a dynamic array. Its capacity can grow dynamically compared to the array in Java. Dynamically growing memory, similar to the dynamic request memory in C language.
When creating an array, it is necessary to determine its size, and the system will open a contiguous space in memory to hold the array, so the array is fixed and cannot be changed dynamically. ArrayList, based on the advantages of preserving arrays for quick lookups, makes up for the drawbacks of arrays to add elements to arrays after they are created. The basic methods of implementation are as follows:
1. Quick find: The sequential storage structure is used on physical memory, so you can quickly find elements based on the index.
2. Capacity dynamic growth: When the array capacity is insufficient (table 1), create a new array larger than the original array (table 2), the elements in the array "move" to the new Array (table 3), and then put the new elements into the new array (table 4), and finally assign the new array to the original array. (from left to right, table 1, table 2, table 3, table 4)
Second, the ArrayList inheritance relations
ArrayList inherits from Abstractlist, implements the list, randomaccess, cloneable, java.io.Serializable these interfaces.
publicclass ArrayList<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, java.io.Serializable { }
ArrayList and collection relationships such as solid lines represent inheritance, dashed lines represent implementations of interfaces:
- Abstractlist provides the default implementation of the list interface (an individual method is an abstract method).
- The list interface defines the methods that lists must implement.
- Implements the Randomaccess interface: Provides a random access function. Randmoaccess is used in Java to be implemented by the list, providing quick access to the list. In the ArrayList, we can quickly get the element object by the ordinal of the element, which is fast random access.
- Implements the Cloneable interface: You can call the Object.clone method to return a shallow copy of the object.
- Implements the Java.io.Serializable interface: It can enable its serialization function, which can be transmitted by serialization. Classes that do not implement this interface will not be able to serialize or deserialize any of their states. The serialized interface has no methods or fields and is used only to identify the semantics of serializable.
Third, the realization of ArrayList
For ArrayList, it implements the list interface, and the underlying uses an array to hold all the elements. Its operation is basically an array of operations. The following is a detailed description:
1. Private properties
// 保存ArrayList中数据的数组privatetransient Object[] elementData;// ArrayList中实际数据的数量privateint size;
It is easy to understand that Elementdata stores the elements within the ArrayList, and the size represents the number of elements that it contains.
There is a key word to explain: transient.
Java's serialization provides a mechanism for persisting object instances. When persisting an object, there may be a special object data member, and we do not want to use the serialization mechanism to save it. In order to turn off serialization on a domain of a particular object, you can precede the field with the keyword transient.
2. Constructors
ArrayList provides three ways to construct an empty list that specifies the initial capacity, constructs an empty list with a default initial capacity of 10, and constructs a list of elements that contain the specified collection. These elements are arranged in the order in which they are returned by the collection iterator.
//ArrayList with capacity-size constructors. Public ArrayList(intinitialcapacity) {Super();if(Initialcapacity <0)Throw NewIllegalArgumentException ("Illegal capacity:"+ initialcapacity);//Create a new array This. Elementdata =NewObject[initialcapacity]; }//ArrayList constructor. The default capacity is 10. Public ArrayList() { This(Ten); }//Create a ArrayList that contains collection Public ArrayList(collection<? extends e> c) {elementdata = C.toarray (); size = Elementdata.length;//C.toarray might (incorrectly) not return object[] (see 6260652) if(Elementdata.getclass ()! = object[].class) Elementdata = arrays.copyof (elementdata, size, object[].class); }
3. Element Storage
ArrayList is an array-based implementation, when the element is added, if the array is large, then the value of a position is set to the specified element, if the array capacity is not enough, to add (e) As an example, you can see that add (e) in the first call to Ensurecapacity (size+1 ) method, then assigns the index of the element to Elementdata[size], and then the size is self-increment. For example, when first added, size 0,add elementdata[0] is assigned to E, and size is set to 1 (similar to executing the following two statements elementdata[0]=e;size=1). Assigning an element's index to elementdata[size] is not the case that the array is out of bounds? The key here is in Ensurecapacity (size+1).
The specific implementation is as follows:
(1) when the following two methods are called to add an element to an array, the default is to add to the back of the last element in the array. The memory structure changes as follows:
//Add element e Public Boolean Add(e) {//Determine the capacity size of the ArrayListEnsurecapacity (size +1);//increments modcount!! //Add E to ArrayListelementdata[size++] = e;return true; }//Append set C to ArrayList Public Boolean AddAll(collection<? extends e> c) {object[] a = C.toarray ();intNumnew = A.length; Ensurecapacity (size + numnew);//increments ModcountSystem.arraycopy (A,0, Elementdata, size, numnew); Size + = Numnew;returnNumnew! =0; }
(2) when the following two methods are called to add an element or a collection to an array, the index position is looked up, the element is added to the index, and the element following the pre-addition index is appended to the new element.
//Add E to the specified location of the ArrayList Public voidAddint Index, E Element) {if(Index> Size | |Index<0)Throw NewIndexoutofboundsexception ("Index:"+Index+", Size:"+ size); Ensurecapacity (size +1);//increments modcount!!System.arraycopy (Elementdata,Index, Elementdata,Index+1, Size-Index); elementdata[Index] = element; size++; }//Starting from the index position, add the collection C to the ArrayList Public BooleanAddAll (int Index, collection<? Extends e> c) {if(Index> Size | |Index<0)Throw NewIndexoutofboundsexception ("Index:"+Index+", Size:"+ size); Object[] A = C.toarray ();intNumnew = A.length; Ensurecapacity (size + numnew);//increments Modcount intnummoved = Size-Index;if(Nummoved >0) System.arraycopy (Elementdata,Index, Elementdata,Index+ numnew, nummoved); System.arraycopy (A,0, Elementdata,Index, numnew); Size + = Numnew;returnNumnew! =0; }
(3) Calling this method will replace the element with the index position with the new element
// 设置index位置的值为element public E set(intindex, E element) { RangeCheck(index); E oldValue = (E) elementData[index]; elementData[index] = element; return oldValue; }
4. Element reading
// 返回此列表中指定位置上的元素。 public E get(intindex) { RangeCheck(index); return (E) elementData[index]; }
5. Element deletion
ArrayList provides two ways to delete functions based on subscript or specified object. As follows:
Romove (int index), first checks the scope, modifies the modcount, retains the element that will be removed, moves the element after the removed position forward one position, leaves the list end element empty (null), and returns the element that was removed.
//delete arraylist specified position element E Remove (int index ) {Rangecheck ( index ); modcount++; E OldValue = (e) elementdata[index ]; int nummoved = size-index -1 ; if (Nummoved > 0 ) System.arraycopy (Elementdata, index + 1 , Elementdata, index , nummoved); Elementdata[--size] = null ; //let GC do it work return oldValue; }
6. Adjust the array capacity ensurecapacity
(1) from the code described above to store elements in the ArrayList, we see that whenever an element is added to an array, it is necessary to check whether the number of elements added will exceed the length of the current array, and if so, the array will be expanded to meet the need to add data. Array expansion is achieved through a public method ensurecapacity (int mincapacity). Before actually adding a large number of elements, I can also use ensurecapacity to manually increase the capacity of the ArrayList instance to reduce the number of incremental redistribution.
//Determine the capacity of the arrarlist. //If ArrayList capacity is insufficient to accommodate all current elements, set new capacity = "(Raw capacity x3)/2 + 1" Public void ensurecapacity(intmincapacity) {//Will be "modified statistics" +1modcount++;intoldcapacity = Elementdata.length;//If the current capacity is not sufficient to accommodate the current number of elements, set the new capacity = "(Raw capacity x3)/2 + 1" if(Mincapacity > Oldcapacity) {Object olddata[] = elementdata;intNewcapacity = (Oldcapacity *3) /2+1;if(Newcapacity < mincapacity) newcapacity = mincapacity; Elementdata = arrays.copyof (Elementdata, newcapacity); } }
As can be seen from the above code, when the array is expanded, the elements in the old array are re-copied to the new array, each time the capacity of the array increases by approximately 1.5 times times its original capacity. The cost of this kind of operation is very high, so we should try our best to avoid the expansion of the array capacity in actual use. When we can predict the number of elements to be saved, we specify their capacity when constructing ArrayList instances to avoid the occurrence of array expansion. or by calling the Ensurecapacity method to manually increase the capacity of the ArrayList instance, depending on the actual demand.
(2) ArrayList also provides us with the ability to adjust the capacity of the underlying array to the size of the actual elements saved by the current list. It can be implemented by means of the TrimToSize method. The code is as follows:
// 将当前容量值设为 =实际元素个数 publicvoidtrimToSize() { modCount++; int oldCapacity = elementData.length; if (size < oldCapacity) { elementData = Arrays.copyOf(elementData, size); } }
Since the length of the Elementdata is extended, the size tag is the number of elements contained therein. So there will be a small size but elementdata.length a large situation, there will be wasted space. TrimToSize will return a new array to Elementdata, the element content remains unchanged, length and size are the same, saving space.
7. Two methods for converting to static array ToArray
(1) calling arrays.copyof will return an array whose contents are elements of size elementdata, that is, copying Elementdata from 0 to size-1 and returning the element to the new array.
// 返回ArrayList的Object数组 publictoArray() { return Arrays.copyOf(elementData, size); }
(2) if the length of the passed-in array is less than size, a new array is returned, sized to size, and the same type as the incoming array. The passed-in array length is equal to size, then the elementdata is copied into the incoming array and returned to the incoming array. If the passed-in array is longer than size, the first size element of the returned array will be empty, in addition to copying Elementdata.
//Returns an array of ArrayList templates. So-called template arrays, that is, you can set T to any data typePublic <T> T[]ToArray (T[]A) {//If the size of array a < The number of ArrayList elements; //Create a new t[] array, the array size is "number of elements ArrayList" and copy All "ArrayList" to the new array if(A.length<size)return(T[])Arrays.CopyOf (Elementdata,size,A.GetClass ());//If the size of array a >= the number of ArrayList elements; //Copy all elements of ArrayList to array A. System.Arraycopy (Elementdata,0A0,size);if(A.length>size) A[Size]= NULL;returnA }
8. Cloneable interface for data shallow copy
// 克隆函数 publicclone() { try { super.clone(); // 将当前ArrayList的全部元素拷贝到v中 v.elementData = Arrays.copyOf(elementData, size); 0; return v; catch (CloneNotSupportedException e) { // this shouldn‘t happen, since we are Cloneable thrownew InternalError(); } }
9. Implement the Serializable interface to enable its serialization function
write function for//java.io.Serializable //ArrayList "capacity, all element values" are written to the output stream Private void writeobject(Java.io.ObjectOutputStream s)throwsjava.io.IOException {//Write out element count, and any hidden stuff intExpectedmodcount = Modcount; S.defaultwriteobject ();//write "Capacity of array"S.writeint (elementdata.length);//write "Every element of an array" for(inti =0; i < size; i++) S.writeobject (Elementdata[i]);if(Modcount! = expectedmodcount) {Throw NewConcurrentmodificationexception (); } }///java.io.Serializable read function: read out according to the Write method read "Capacity" of ArrayList first, then read "All element values" Private void ReadObject(Java.io.ObjectInputStream s)throwsJava.io.IOException, ClassNotFoundException {//Read in size, and any hidden stuffS.defaultreadobject ();//Read the ArrayList "capacity" from the input stream intArraylength = S.readint (); Object[] A = Elementdata =NewObject[arraylength];//reads "All element values" from the input stream for(inti =0; i < size; i++) A[i] = S.readobject (); }
Java ArrayList Implementation principle