Interview questions often ask the difference between LinkedList and ArrayList, and the back of the online nonsense, rather than directly to the source!
Article source from Jre1.8,java.util.arraylist
Since the analysis, mainly for the structure of the internal implementation of the principle and some of the main methods to explain, as for the I/O and advanced features are temporarily skipped.
Variable/constant
First look at the defined (static) variables:
classArraylist2<e>//extends Abstractlist<e>//implements Randomaccess, Cloneable, java.io.Serializable{ Private Static Final LongSerialversionuid = 8683452581122892189L; Private Static Final intDefault_capacity = 10; Private Static Finalobject[] Empty_elementdata = {}; Private Static Finalobject[] Defaultcapacity_empty_elementdata = {}; transientobject[] Elementdata; Private intsize;}
Here at the beginning of the definition of 6 variables, the first one with serialization related no tube, the remaining 5 to explain in turn:
Default_capacity: Initialize default size for container ArrayList
Object[] Empty_elementdata: An empty array that is used after some method calls (for example, RemoveAll)
object[] Defaultcapacity_empty_elementdata: Default empty array, default to this when no parameter is initialized
Object[] Elementdata: Holds the contents of the current ArrayList, which is marked as a serialization ignore object
int Size: It is obvious that the current ArrayList size
It is important to note that several of them are marked as static final variables.
constructor function
After reading the variables, look at the constructor section, the constructor has 3 overloaded versions, respectively, described below.
1. Non-parametric version
Public ArrayList () { this. elementdata = defaultcapacity_empty_elementdata; }
If you initialize a ArrayList directly without passing any parameters, you will get the default empty array above.
2, int version
PublicArrayList (intinitialcapacity) { //normally, an array of a specified size is initialized if(Initialcapacity > 0) { This. Elementdata =NewObject[initialcapacity]; } //Pass 0 is the same as the non-transmission in the implementation Else if(initialcapacity = = 0) { This. Elementdata =Empty_elementdata; } //It's just an anomaly . Else { Throw NewIllegalArgumentException ("Illegal capacity:" +initialcapacity); } }
This is basically the most common case where the internal implementation is the normal array.
3. Collection version
PublicArrayList (collection<?extendsE>c) {//convert a collection to an array and assign to a local variableElementdata =C.toarray (); if((size = elementdata.length)! = 0) { //C.toarray might (incorrectly) not return object[] (see 6260652) if(Elementdata.getclass ()! = object[].class) Elementdata= arrays.copyof (elementdata, size, object[].class); } Else { //an empty collection is equivalent to an empty array This. Elementdata =Empty_elementdata; } }
If the initialization is passed into a collection, the set is co-ArrayList as the initial value.
There is a bug where the ToArray method returns not necessarily an object, although it is by default, but not necessarily if overridden.
Detailed questions can be seen in another blog: http://blog.csdn.net/gulu_gulu_jp/article/details/51457492
If the return is not of type object, it will be transformed upward.
Method
Next, look at the common methods.
The first is the Get/set method:
Public E get (int index) { Rangecheck (index); return Elementdata (index); }
Public E set (int index, e Element) { Rangecheck (index); = Elementdata (index); = element; return oldValue; }
You can see the very simple violence, first the scope check, and then return/set the element corresponding to index.
Simply look at the Rangecheck:
Private void rangecheck (int index) { if (index >= size) Throw New indexoutofboundsexception (outofboundsmsg (index)); }
It is also very simple, mainly to determine whether the index given is larger than the size of the array, or throw an exception.
Get the corresponding value, not directly with Elementdata[index], but instead use a method Elementdata (), looking a little mixed, look at the method definition:
e elementdata (int index) { return (E) elementdata[index]; }
The method actually simply converts the values that are taken out to ensure that the return type is accurate.
Next is the Add/remove method.
Both of these methods have overloaded versions, but they are not complex and are used more.
First, look at the one parameter version of Add, which inserts the given element at the tail.
Public Boolean Add (e e) { + 1); // increments modcount!! elementdata[size++] = e; return true ; }
A little bit about the source code comment Modcount, this variable is derived from the java.util.AbstractList, specifically to calculate the number of times the container was changed, for me this rookie user is useless.
This will first detect the capacity of the container, then add the element at the tail and add the size to 1.
Look at the Ensurecapacityinternal method:
Private void ensurecapacityinternal (int mincapacity) { if (elementdata = = Defaultcapacity_empty_elementdata) { = Math.max (default_capacity, mincapacity); } Ensureexplicitcapacity (mincapacity); }
Originally this is a purse function, when the array element is empty, the parameter correction, because the container's default size is 10, so the capacity of less than 10 is detected.
After correction, the parameters of 10 or larger than 10 are passed into the ensureexplicitcapacity for detection:
Private void ensureexplicitcapacity (int mincapacity) { modcount+ +; if (Mincapacity-elementdata.length > 0) grow (mincapacity); }
This also looks like a purse method, but not if the current container size has reached the upper limit, it calls grow for expansion:
private void Grow (int mincapacity) { int ol dcapacity = elementdata.length; int newcapacity = oldcapacity + (oldcapacity >> 1); if (newcapacity-mincapacity < 0) n ewcapacity = mincapacity; if (newcapacity-max_array_size > 0) newcapacity = hugecapacity (mincapacity); Elementdata = arrays.copyof (Elementdata, newcapacity); }
Actually here the formal parameter name I think is not particularly good, should call the minimum required capacity, namely minneededcapacity.
This is the first to get the current container size, and to expand, the expansion here is calculated as follows:
Oldcapacity + (oldcapacity >> 1)
That is, if the previous 10, then the new capacity is Ten + Math.floor (10/2) = 15.
The new capacity will be compared with the required capacity, if not enough, then simply take the required capacity for the new capacity.
The second if is to determine if the capacity after expansion is greater than the maximum (array can be reached) integer, see the definition of max_array_size variable to understand:
/** * The maximum size of array to allocate. * Some VMs Reserve Some header words in an array. * Attempts to allocate larger arrays could result in * outofmemoryerror:requested array size exceeds VM limit */ Private Static Final int Max_array_size = integer.max_value-8;
It is necessary to take a look at the comments here, simply to say that some jvms add something to the array, so the array size is actually smaller than the theory. This is easy to understand, such as computer hard disk, capacity 100G, usable capacity in fact will be a discount, a reason.
For completeness, take a look at the internal implementation of the Hugecapacity function:
Private Static int hugecapacity (int mincapacity) { if// overflow Throw New OutOfMemoryError (); return (Mincapacity > Max_array_size)? integer.max_value: max_array_size; }
Parameter detection is fun, internal use of the function is also afraid of passing negative numbers.
This will compare the required capacity with the maximum usable security capacity, if there is no way, the capacity is set to the maximum usable capacity, I do not know if there will be a problem here.
Back to the Grow method, after the new capacity, will call the Arrays.copyof method, which is the method of another class inside the package, the internal implementation is to call System.arraycopy directly memory replication, high efficiency, and finally return a new array, size for the increased capacity.
Next, look at the second overloaded Add method:
Public void Add (int Index, E Element) { Rangecheckforadd (index); + 1); // increments modcount!! System.arraycopy (Elementdata, index, Elementdata, index + 1, - index); = element; Size+ +; }
The detection here is not quite the same, one more step, but a look at the method will understand:
Private void rangecheckforadd (int index) { if (Index > Size | | | Index < 0) thrownew indexoutofboundsexception (outofboundsmsg (index)); }
Because this overloaded method is inserted, a numeric test is required, if the insertion index is larger than the array size or less than 0, throw an exception.
Next is the regular capacity detection.
The next step is to refer to the previously mentioned system.arraycopy, which will copy all the elements after index +1 to the source array, for a simple example:
If the original array is [1,2,3,4], assuming that the index is 1, after this step, the array becomes [1,2,2,3,4].
Finally, the value of the corresponding index is assigned to the given value, size++.
As you can see, inserting an element in the middle of an array is time-consuming and changes the number of elements behind the index.
The
Next is remove, which also has 2 overloads, one to delete the given index, and one to delete the given element:
public E Remove (int index) {Rangecheck (index); Modcount ++; E oldValue = Elementdata (index); int nummoved = Size-index-1; if (nummoved > 0 +1, Elementdata, index, nummoved); elementdata[--size] = null ; // clear to let GC do it work return OldValue; }
Nothing to say, ignore the detection, a word summary is to copy all the elements of the corresponding index-1 to the original array, and then size-1, and the end of the element NULL let the GC recycling, and finally return to delete the element.
Public BooleanRemove (Object o) {if(O = =NULL) { for(intindex = 0; index < size; index++) if(Elementdata[index] = =NULL) {fastremove (index); return true; } } Else { for(intindex = 0; index < size; index++) if(O.equals (Elementdata[index])) {fastremove (index); return true; } } return false; }
This is the second overload, special handling of NULL, and this strange thing can only be compared by = =.
In general, it is the traversal of the array, if a matching element is found, the Fastremove is successful, the deletion returns true, otherwise false.
This quick delete is nothing to be curious about:
Private void fastremove (int index) { Modcount++ ; int nummoved = size-index-1; if (nummoved > 0) System.arraycopy (elementdata, index+1, Elementdata, index, nummoved); elementdata[null// clearto let GC do it work }
Similar to the first overloaded remove, it just removes the processing of range detection and return values faster.
The rest of the methods are most of the above variants, there is no need to study, interested in the source can read their own.
Analysis of Java source code ArrayList