Analysis of Java source code ArrayList

Source: Internet
Author: User
Tags serialization

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

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.