Write annotation series for JDK jdk1.6 container (1): ArrayList source Analysis

Source: Internet
Author: User
Tags addall array length int size serialization

The original source from the devouring world, links organized from importnew

Write annotation series for JDK jdk1.6 container (2): LinkedList source Analysis
Write annotation series for JDK jdk1.6 container (3): Iterator design mode
Write annotation series to JDK jdk1.6 container (4)-hashmap source analysis
Write annotation series to JDK jdk1.6 container (5)-linkedhashmap Source analysis
Write annotation series for JDK jdk1.6 container (6)-hashset Source Analysis &map iterator

Write annotation series for JDK jdk1.6 container (1): ArrayList source Analysis

Work often hear people say "container", a variety of containers, what is the bottom of the container, the popular saying "container is used to install things containers, such as: bucket is used to hold water, bucket is a container." ”

OK, when we write the program, we often have to manage a large number of objects, such as query, traversal, modification and so on. The container provided by the JDK is located in the Java.util package and is one of the most commonly used packages.

But why not use arrays (in fact, not without, but not directly), because the length of the array needs to be determined in advance, and can not change the size of the hands and feet are limited.

Let's get to the bottom of the list, and first we think about what functions an object manages the container. Add, delete, modify, query (crud right). ) and so on. Traversal, capacity, whether or not to contain an element ...

The function is there, if you allow yourself to implement a container like this how to achieve it.

Let's see how ArrayList implements these functions.

1. Define

First, let's look at the definition of the top-level interface collection,

Public interface Collection<e> extends iterable<e> {
    int size ();
    Boolean IsEmpty ();
    Boolean contains (Object o);
    Iterator<e> iterator ();
    Object[] ToArray ();
    <T> t[] ToArray (t[] a);
    Boolean Add (e e);
    Boolean remove (Object o);
    Boolean containsall (collection<?> c);
    Boolean AddAll (collection< extends e> c);
    Boolean RemoveAll (collection<?> c);
    Boolean retainall (collection<?> c);
    void Clear ();
    Boolean equals (Object O);
    int hashcode ();
}

Then there is the definition of interface list,

Public interface list<e> extends collection<e> {int size ();
         Boolean IsEmpty ();
         Boolean contains (Object O);
         Iterator<e> iterator ();
         Object[] ToArray ();
         <T> t[] ToArray (t[] a);
         Boolean Add (e e);
         Boolean remove (Object O);
         Boolean containsall (collection<?> c);
         Boolean AddAll (collection< extends e> c);
         Boolean addall (int index, COLLECTION&LT;? extends e> c);
         Boolean RemoveAll (collection<?> c);
         Boolean retainall (collection<?> c);
         void Clear ();
         Boolean equals (Object O);
         int hashcode ();
         E get (int index);
         e Set (int index, e element);
         void Add (int index, E element);
         E Remove (int index);
         int indexOf (Object o);
         int LastIndexOf (Object o);
         Listiterator<e> Listiterator ();
      listiterator<e> listiterator (int index);   list<e> sublist (int fromindex, int toindex); }

Then look at the definition of ArrayList,

public class Arraylist<e> extends abstractlist<e> implements List<e>, Randomaccess, Cloneable, Java.io.Serializable

You can see that ArrayList inherits Abstractlist (this is an abstract class, encapsulates some of the underlying list operations), implements List,randomaccess,cloneable,serializable several interfaces, Randomaccess is a markup interface used to indicate that it supports fast random access.

2. Underlying storage
As the name suggests, ArrayList is an array of the list container, since it is implemented with an array, of course, the bottom of the array to save the data ...

Private transient object[] elementdata;
private int size;

You can see Using an object array to store the data, counting with an int value to record the current container's data size.

In addition, careful people will find that the Elementdata array is decorated with transient, the function of the transient keyword is simply that Java has its own default mechanism for serialization, the properties of which are decorated do not need to be maintained.

Will have a little doubt. Elementdata does not need to be maintained, then how to deserialize and how to ensure the correctness of serialization and deserialization of data. Don't need to store. Think of it with your thighs that is certainly not possible, since the need to store, it is how to achieve it. Notice the red bold on the top, the default serialization mechanism, um, yes, I figured it out. ArrayList must have used a custom serialization method. Look at the following two methods:

/** * Save The state of the ' <tt>ArrayList</tt> instance to a stream (which is, serialize it). * * @serialData The length of the array backing the <tt>arraylist </tt> * instance is E mitted (int), followed by all of it elements * (each a <tt>Object</tt>) in the proper Orde  R. */private void WriteObject (Java.io.ObjectOutputStream s) throws java.io.ioexception{//Write
       Out element count, and any hidden stuff int expectedmodcount = Modcount;

        S.defaultwriteobject ();

        Write out Array length s.writeint (elementdata.length);
        Write out all elements in the proper order.

        for (int i=0; i<size; i++) S.writeobject (elementdata[i));
        if (Modcount!= expectedmodcount) {throw new concurrentmodificationexception (); }/** * Reconstitute the <tt>ArrayList</tt> INstance from a stream (which is, * deserialize it).
        * * private void ReadObject (Java.io.ObjectInputStream s) throws Java.io.IOException, ClassNotFoundException {

        Read in size, and any hidden stuff s.defaultreadobject ();
        Read in array length and allocate array int arraylength = S.readint ();

        Object[] A = Elementdata = new Object[arraylength];
        Read in the ' all elements ' proper order.
    for (int i=0; i<size; i++) A[i] = S.readobject (); }

The English annotation is very detailed, also easy to read, will not translate. Then think about why this design, it is not very troublesome. Here's a simple explanation:

Elementdata is an array of data stores, and the array is fixed-length, it will initialize a capacity, such as capacity is insufficient to expand capacity (expansion mode for the data copy, will be explained in detail later), the more popular point is that for example, the length of the Elementdata is 10, and the inside only saved 3 objects, Then the remaining 7 elements of the array (null) are meaningless, so there is no need to save, to save the serialized memory capacity, so here you can understand the purpose and benefits of this design, by the way, it seems to understand the length of a separate int variable save, Instead of directly using Elementdata.length.

3. Construction method

/**
     * Constructs a list */public
    ArrayList (int initialcapacity) {
        super ()
        with a specified capacity; if (initialcapacity < 0)
            throw new IllegalArgumentException ("illegal Capacity:" +
                                               initialcapacity);
        This.elementdata = new object[initialcapacity];
    }

    /**
     * Constructs a list/public ArrayList () with an initial capacity of 10
    () {this
        ;
    }

    /**
     * Constructs a list containing the specified elements, which are arranged in the order in which the Collection iterator returns
    (collection<? extends E > C) {
        elementdata = C.toarray ();
        Size = elementdata. length;
        C.toarray might (incorrectly) not return object[] (= 6260652)
        if (elementdata. GetClass ()!= object[].class) 
  elementdata = arrays.copyof (elementdata, size, object[].class);
    }

The construction method is finished, think about the meaning of the construction method of the specified capacity, since the default is 10 then why provide a construction method that can specify the size of the capacity? It seems a bit too early to say here, then sell a case, the following say ...

4. Increase

/** * Add an element */public Boolean Add (e e) {//expansion check ensurecapacity (size + 1);
        Increments Modcount//add E to the data tail of list, capacity +1 Elementdata[size + +] = e;
    return true;
        /** * Add an element at the specified location/public void Add (int index, E Element) {//To determine whether the index is out of bounds, and how familiar exceptions are thrown here ... if (Index > Size | | Index < 0) throw new Indexoutofboundsexception ("Index: +index+"

       , Size: "+size);  Carry out the expansion check ensurecapacity (size+1); The increments Modcount//array is replicated for the purpose of inserting the element at the location of the index and then shifting the elements after the index to a location System.
       Arraycopy (Elementdata, index, Elementdata, index + 1, size-index);
       Assigns the specified index position to element elementdata[index] = element;
    List capacity +1 size++; /** * Add a SET element/public boolean addall (collection<? extends e> c) {//convert C to array Obj
        Ect[] A = C.toarray (); int numnew = A.length ;  Expansion check ensurecapacity (size + numnew); Increments Modcount//adds C to the data tail System of the list.
       Arraycopy (A, 0, elementdata, size, numnew);
        Update current container size = = Numnew;
    return numnew!= 0;  /** * At the specified position, add a SET element/public boolean addall (int index, COLLECTION&LT;? extends e> c) {if (Index > Size | | Index < 0) throw new Indexoutofboundsexception ("Index: + index +", S

       Ize: "+ size);
        Object[] A = C.toarray ();
       int numnew = A.length;  Ensurecapacity (size + numnew);
       Increments Modcount//calculate the length to be moved (number of elements after index) int nummoved = Size-index; Array replication, vacated by the position of index to Index+numnum, the element after the index of the array to the right to move numnum position if (nummoved > 0) System.

       Arraycopy (Elementdata, index, elementdata, index + numnew, nummoved); Copies the element of the collection that will be inserted into the array's vacated position in the System. Arraycopy (A, 0, Elementdata, index, numnew);
        Size + = Numnew;
    return numnew!= 0;
       /** * Array capacity check, when not enough to expand * * public void ensurecapacity (int mincapacity) {modcount++;
       The length of the current array int oldcapacity = elementdata. length;
          The minimum required capacity is greater than the current array length to enlarge if (Mincapacity > Oldcapacity) {Object olddata[] = elementdata;
          The new expansion of the array length of the old capacity of 1.5 times times +1 int newcapacity = (oldcapacity * 3)/2 + 1; If the newly expanded array length is smaller than the minimum required capacity, the capacity is expanded to the minimum required size if (Newcapacity < mincapacity) Newcapacity = Mincapa
            City
            Mincapacity is usually close to size, so this is a win://Data copy, arrays.copyof bottom implementation is system.arraycopy ()
       Elementdata = arrays.copyof (Elementdata, newcapacity); }
    }

5. Delete

    /** * Delete element according to index position/public E-Remove (int index) {//array out of bounds Check Rangecheck (index);
      modcount++;
       Remove the element to remove the location for return using e OldValue = (e) elementdata[index];
       Counts the number of integers to be copied int nummoved = size-index-1; Array replication, which is to move the element after index forward one position if (nummoved > 0) System.
       Arraycopy (Elementdata, index+1, Elementdata, Index, nummoved);  Empty the last element of the array (because an element is deleted, then the elements behind the index move forward, so the last one is useless), so that the GC can be recycled as soon as possible/don't forget size minus one elementdata[--size] = null;
    Let GC does its work return oldValue; }/** * Deletes from element content, deletes only the first/public boolean remove (Object o) {//pairs of elements to be deleted//pair data
        element to traverse Lookup, know to find the first element to be deleted, delete after the return, if the element to be deleted is just the last one that's miserable, time complexity can reach O (n) ... if (o = = null) {for (int index = 0; index < size; index++)//null value use = = Comparison if (elementdata [index] = null) {Fastremove (iNDEX);
              return true;
               } else {for (int index = 0; index < size; index++)//non-null of course, it's compared to equals.
                  if (O.equals (Elementdata [index])) {fastremove (index);
              return true;
    return false;
     }/* Private Remove method, skips bounds checking and does not * return the value removed.
       * * private void Fastremove (int index) {modcount++;
        The principle is the same as before add, or the array copy, will be the element of the index moved forward a position, not fine explanation, int nummoved = size-index-1; if (nummoved > 0) System.
        Arraycopy (Elementdata, index+1, Elementdata, Index, nummoved); Elementdata[--size] = null; Let GC does its work}/** * array out of bounds check/private void Rangecheck (int index) {if (Index > = size) throw new Indexoutofboundsexception ("Index:" +indeX+ ", Size:" +size); }

PS: See this method, it can be JDK source code in some places is not so delicate, for example, when removed, the array is checked out of bounds to a single method, but flip forward the array in the Add method is not encapsulated, the need to check the time is to write the same code, why ah ...

Add and Remove methods here is the explanation, the code is very simple, the main needs of special concern on two places: 1. Array expansion, 2. Array replication, both of which are extremely efficient and most miserable (added to the first position in the list, Delete the last element of the list or delete the element at the first index position of the list the time complexity is up to O (n).

Remember that pit up there? (why provide a construction method that can specify the size of the capacity). See here is not a little understand, simple explanation: If the array initial capacity is too small, assuming the default of 10 sizes, and we use the main operation of ArrayList to increase the element, constantly increase, has been increased, non-stop increase, will appear above the consequences. That is, array capacity is constantly being challenged, the array needs to be continuously expanded, the process of expansion is the process of array copy system.arraycopy, each expansion will open up a new memory space and data replication movement, which is bound to affect performance. Then in this write-oriented (will be expanded, delete will not shrink) in the scene, ahead of the predictable setting of a large capacity, you can reduce the number of expansion, improve performance.

The above two graphs are the process of array expansion and the duplication of arrays, and it should be noted that array expansion is accompanied by opening up new memory space to create a new array and then data replication, while array replication does not need to open new memory space, just copy the data.

It is said that the addition of elements may be expanded, and the deletion of elements will not be indented, if the deletion of the main scene using the list, has been constantly deleted and rarely increased, then what will happen. Again or after a large expansion of the array, we only use a few space, will appear above. Of course, it's a waste of space.

    /**
     * To free up space by adjusting the capacity of the underlying array to the size of the current actual element.
     * * Public
    void TrimToSize () {
        modcount++
       ; The capacity of the current array
        int oldcapacity = elementdata. length;
       If the current actual element size is less than the current array's capacity, indent
        if (size < oldcapacity) {
            elementdata = arrays.copyof (elementdata, size); 
  
   }
  

6. Update

/**
     * Updates the element at the specified position to the new element
    /public E set (int index, e element) {
       //array out of bounds check
       rangecheck (index);

       Remove the element to update the location for return using
       e OldValue = (e) elementdata[index];
       Assign the position to the element of the row (
        elementdata[index] = elements
       ; Returns the old element return
        OldValue;
    }

7. Find

/**
     * Find the element at the specified position/public
    E get (int index) {
       Rangecheck (index);

        Return (E) elementdata [index];
    }

Because ArrayList is implemented using arrays, updates and lookups are straightforward based on subscript operations.

8. Whether to include

/** * Returns <tt>true</tt> If this list contains the specified element. * More formally, returns <tt>true</tt> if and only if this list contains * At least one element <tt&gt
     ;e</tt> such that * <tt> (o==null e==null:o.equals (e)) </tt>. * * @param o element whose presence in this list are to being tested * @return <tt> true</tt> If this Li
    ST contains the specified element */public Boolean contains (Object o) {return indexOf (O) >= 0; }/** * Returns the index of the ' the ' of the ' the ' of the ' the specified element * in this list, or-1 if this Li
     St does not contain the element. * More formally, returns of the lowest index <tt>i</tt> such that * <tt> (o==null. Get (i) ==null:o.eq
     Uals (Get (i))) </tt>, * or-1 If there is no such index. */public int indexOf (Object o) {if (o = = null) {for (int i = 0;; Size
       i++) if (Elementdata [i]==null) return i; else {for (int i = 0; i < size; i++) if (O.equals (Elementdata [i])) Retu
       RN I;
    } return-1; }/** * Returns The index of the last occurrence of the specified element * in this list, or-1 if this LIS
     T does not contain the element. * More formally, returns of the highest index <tt>i</tt> such that * <tt> (o==null. Get (i) ==NULL:O.E
     Quals (Get (i))) </tt>, * or-1 If there is no such index.
               */public int lastindexof (Object o) {if (o = = null) {for (int i = size-1; I >= 0; i--)
       if (Elementdata [i]==null) return i; else {for (int i = size-1 i >= 0; i--) if (O.equals (Elementdata [i])) r
       Eturn i;
    } return-1; }

Contains is mainly to check the indexof, which is the element in the list of the index position is the array subscript, and then see IndexOf and LastIndexOf code is not very familiar with, yes, and public booleanremove (Object o) Code, is the element null judgment, is a cyclic comparison, not much said ... But you know, the worst case scenario (the last one to look for) is very bad ...

9. Capacity Judgment

/** * Returns The number of elements in this
     list.
     * * @return The number of elements in this
     list *
     /public
    int size () {return
        size;
    }

    /**
     * Returns <tt>true</tt> If this list contains no elements.
     *
     * @return <tt> true</tt> If this list contains no elements
    /public boolean isempty () {
  
   return size = = 0;
    }
  

Because the size is used for counting, it is really great to find the list sizes to get and judge ...

OK, so ArrayList's analysis and comments are basically done. What's the difference? Yes, Modcount is doing, how to operate the variable everywhere, there are traversal, why not speak. Because the iterator traversal is relatively complex, and iterator is a GOF classic design mode is more important, then will be iterator separate analysis, here is not long-winded ...

ArrayList, Finish.

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.