Arraylist source code analysis for set learning

Source: Internet
Author: User

Arraylist source code analysis for set learning

ArrayList is a variable array implementation of the List interface. All optional list operations are implemented, and all elements including null are allowed. In addition to the List interface, this class also provides some methods to internally store the size of the List array.

Each ArrayList instance has a capacity, which is the size of the array used to store list elements. It is always equal to at least the size of the List (if capacity is not specified, the default value is 10 ).

/**     * Constructs an empty list with an initial capacity of ten.     */    public ArrayList() {    this(10);    }
As elements are added to the ArrayList, their capacity increases automatically. Automatic growth will result in a re-copy of data to the new array (affecting performance). Therefore, if you can predict the amount of data, you can specify its capacity when constructing the ArrayList. Before adding a large number of elements, the application can also use the ensureCapacity operation to increase the capacity of the ArrayList instance, which can reduce the number of progressive redistribution.

/**     * Appends the specified element to the end of this list.     *     * @param e element to be appended to this list     * @return true (as specified by {@link Collection#add})     */    public boolean add(E e) {    ensureCapacity(size + 1);  // Increments modCount!!    elementData[size++] = e;    return true;    }
/**     * Increases the capacity of this ArrayList instance, if     * necessary, to ensure that it can hold at least the number of elements     * specified by the minimum capacity argument.     *     * @param   minCapacity   the desired minimum capacity     */    public void ensureCapacity(int minCapacity) {    modCount++;    int oldCapacity = elementData.length;    if (minCapacity > oldCapacity) {        Object oldData[] = elementData;        int newCapacity = (oldCapacity * 3)/2 + 1;            if (newCapacity < minCapacity)        newCapacity = minCapacity;            // minCapacity is usually close to size, so this is a win:            elementData = Arrays.copyOf(elementData, newCapacity);    }    }
Note: In ensureCapacity,
Object oldData[] = elementData;
To save the reference of the original array before copying the new array, because the reference will point to the new array. However, it is useless to save it.
elementData = Arrays.copyOf(elementData, newCapacity);
Note that this implementation is not synchronous. If multiple threads access an ArrayList instance at the same time, and at least one thread modifies the list from the structure, it must maintain external synchronization.

Implementation of Arraylist using object arrays at the underlying layer
private transient Object[] elementData;
Constructor
public ArrayList() {    this(10);} public ArrayList(int initialCapacity) {    super();    if (initialCapacity < 0)        throw new IllegalArgumentException("Illegal Capacity: "+ initialCapacity);    this.elementData = new Object[initialCapacity];} public ArrayList(Collection
  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);}

Here we also use Arrays. copyOf to replicate Arrays. It is the same as when a new array is generated.

Storage

First, determine ensureSize. If it is enough, insert it directly. Otherwise, follow the policy extension, copy, and recreate the array.

Step 2 Insert the element.

ArrayList provides set (int index, E element), add (E), add (int index, e element), addAll (Collection C), addAll (int index, Collection C) add these elements. Next we will explain them one by one

1. set (int index, E element), replace, instead of insert, return the replaced element

 /**     * Replaces the element at the specified position in this list with     * the specified element.     *     * @param index index of the element to replace     * @param element element to be stored at the specified position     * @return the element previously at the specified position     * @throws IndexOutOfBoundsException {@inheritDoc}     */    public E set(int index, E element) {    RangeCheck(index);     E oldValue = (E) elementData[index];    elementData[index] = element;    return oldValue;    }
2. add (E e) to add elements to the end. If the size does not overflow, it will automatically increase.
 /**     * Appends the specified element to the end of this list.     *     * @param e element to be appended to this list     * @return true (as specified by {@link Collection#add})     */    public boolean add(E e) {    ensureCapacity(size + 1);  // Increments modCount!!    elementData[size++] = e;    return true;    }
3. add (int index, E element) to add an element to a certain position. All the elements after the index are removed by one
/**     * Inserts the specified element at the specified position in this     * list. Shifts the element currently at that position (if any) and     * any subsequent elements to the right (adds one to their indices).     *     * @param index index at which the specified element is to be inserted     * @param element element to be inserted     * @throws IndexOutOfBoundsException {@inheritDoc}     */    public void add(int index, E element) {    if (index > size || index < 0)        throw new IndexOutOfBoundsException(        "Index: "+index+", Size: "+size);     ensureCapacity(size+1);  // Increments modCount!!    System.arraycopy(elementData, index, elementData, index + 1,             size - index);    elementData[index] = element;    size++;    }
3. The next two methods are to convert the set into an Array Using c. toArray, and then use Arrays. copyOF to focus on the research.
 /**     * Appends all of the elements in the specified collection to the end of     * this list, in the order that they are returned by the     * specified collection's Iterator.  The behavior of this operation is     * undefined if the specified collection is modified while the operation     * is in progress.  (This implies that the behavior of this call is     * undefined if the specified collection is this list, and this     * list is nonempty.)     *     * @param c collection containing elements to be added to this list     * @return true if this list changed as a result of the call     * @throws NullPointerException if the specified collection is null     */    public boolean addAll(Collection
  c) {    Object[] a = c.toArray();        int numNew = a.length;    ensureCapacity(size + numNew);  // Increments modCount        System.arraycopy(a, 0, elementData, size, numNew);        size += numNew;    return numNew != 0;    }
The Collection interface defines the toArray method, as follows:
 /**     * Returns an array containing all of the elements in this collection.     * If this collection makes any guarantees as to what order its elements     * are returned by its iterator, this method must return the elements in     * the same order.     *     * 

The returned array will be "safe" in that no references to it are * maintained by this collection. (In other words, this method must * allocate a new array even if this collection is backed by an array). * The caller is thus free to modify the returned array. * *

This method acts as bridge between array-based and collection-based * APIs. * * @return an array containing all of the elements in this collection */ Object[] toArray();

The following is an implementation of arraylist:
 /**     * Returns an array containing all of the elements in this list     * in proper sequence (from first to last element).     *     * 

The returned array will be "safe" in that no references to it are * maintained by this list. (In other words, this method must allocate * a new array). The caller is thus free to modify the returned array. * *

This method acts as bridge between array-based and collection-based * APIs. * * @return an array containing all of the elements in this list in * proper sequence */ public Object[] toArray() { return Arrays.copyOf(elementData, size); }


Delete

One is to delete an index without any query. The element after the index is moved to the left by one, and the last element is set to null, which is collected by the gc.

 /**     * Removes the element at the specified position in this list.     * Shifts any subsequent elements to the left (subtracts one from their     * indices).     *     * @param index the index of the element to be removed     * @return the element that was removed from the list     * @throws IndexOutOfBoundsException {@inheritDoc}     */    public 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 its work     return oldValue;    }

Arrays. copyOf
  /**     * Copies the specified array, truncating or padding with nulls (if necessary)     * so the copy has the specified length.  For all indices that are     * valid in both the original array and the copy, the two arrays will     * contain identical values.  For any indices that are valid in the     * copy but not the original, the copy will contain null.     * Such indices will exist if and only if the specified length     * is greater than that of the original array.     * The resulting array is of the class newType.     *     * @param original the array to be copied     * @param newLength the length of the copy to be returned     * @param newType the class of the copy to be returned     * @return a copy of the original array, truncated or padded with nulls     *     to obtain the specified length     * @throws NegativeArraySizeException if newLength is negative     * @throws NullPointerException if original is null     * @throws ArrayStoreException if an element copied from     *     original is not of a runtime type that can be stored in     *     an array of class newType     * @since 1.6     */    public static 
 
   T[] copyOf(U[] original, int newLength, Class
   newType) {        T[] copy = ((Object)newType == (Object)Object[].class)            ? (T[]) new Object[newLength]            : (T[]) Array.newInstance(newType.getComponentType(), newLength);        System.arraycopy(original, 0, copy, 0,                         Math.min(original.length, newLength));        return copy;    }
 
Jdk is optimized here. For the object type, the new object Array is used directly. newInstance calls the native method to generate the response array type. After the array is created, the System. arrayCopy implements array replication. System is a final class, And copyof is a native method. (If so, why is the native Method Used ???) The source code is as follows:
* @param      src      the source array.     * @param      srcPos   starting position in the source array.     * @param      dest     the destination array.     * @param      destPos  starting position in the destination data.     * @param      length   the number of array elements to be copied.     * @exception  IndexOutOfBoundsException  if copying would cause     *               access of data outside array bounds.     * @exception  ArrayStoreException  if an element in the src     *               array could not be stored into the dest array     *               because of a type mismatch.     * @exception  NullPointerException if either src or     *               dest is null.     */    public static native void arraycopy(Object src,  int  srcPos,                                        Object dest, int destPos,                                        int length);

Note:

  1. The Native modifier indicates that the implementation of this method is not java, but c ++ or other languages.

    2. It helps improve performance

    About native

    Java is not perfect. In addition to its shortcomings, Java is much slower than traditional C ++ in terms of running speed. In addition, Java cannot directly access the underlying operating system (such as system hardware ), therefore, Java uses the native method to extend the functions of Java programs.

    The native method can be compared to the interface of a Java program and a C program. The implementation steps are as follows:
    1. Declare the native () method in Java and compile it;
    2. Use javah to generate a. h file;
    3. Write a. cpp file to implement the native export method, which must contain the. h file generated in step 2 (note that it contains the jni. h file in JDK );
    4. Compile the. cpp file in step 3 into a dynamic link library file;
    5. Use the System. loadLibrary () method in Java to load the dynamic link library file generated in Step 4. This native () method can be accessed in Java.

    In the preceding example, both System. arrayCopy () and Array. newInsance (compnentType, length) use the native method. The source code of Array. newInstance () is supplemented as follows:

    * @param componentType the Class object representing the     * component type of the new array     * @param length the length of the new array     * @return the new array     * @exception NullPointerException if the specified     * componentType parameter is null     * @exception IllegalArgumentException if componentType is {@link Void#TYPE}     * @exception NegativeArraySizeException if the specified length      * is negative     */    public static Object newInstance(Class
        componentType, int length)    throws NegativeArraySizeException {    return newArray(componentType, length);    }

    private static native Object newArray(Class componentType, int length)    throws NegativeArraySizeException;

    Meaning of Array. newInstance ()

    What is the significance of using Array. newInstance () to create an Array?

    In addition to dynamically determining the types of objects to be created and accessed member variables and methods at runtime, Java reflection technology can also dynamically create arrays of different types and dimensions.

    To dynamically create an array, follow these steps:
    1. Create a Class Object and use the forName (String) method to specify the type of the array element.
    2. Call Array. newInstance (Class, length_of_array) to dynamically create an Array.

    Methods for accessing dynamic array elements are usually different. The format is as follows. Note that the method returns an Object.
    Array. get (arrayObject, index)

    The method for assigning values to dynamic array elements is also different from the normal method. Its format is as follows. Note that the last parameter must be of the Object type.
    Array. set (arrayObject, index, object)

    Dynamic Array can not only create one-dimensional arrays, but also create multi-dimensional arrays. The procedure is as follows:
    1. Define an integer array: for example, int [] dims = new int {5, 10, 15}; specify a three-dimensional array
    2. Call Array. newInstance (Class, dims); Create an Array with the specified dimension

    There is no major difference between the method for accessing Multidimensional Dynamic Arrays and the method for accessing one-dimensional arrays, except that it needs to be obtained multiple times. Each time an Object is retrieved, the assignment is the same until the last time.

    The dynamic Array can be converted to a normal Array, for example:
    Array arry = Array. newInstance (Integer. TYPE, 5 );
    Int arrayCast [] = (int []) array;

    Public static void main (String args []) throws Exception {Class
       ClassType = Class. forName ("java. lang. string "); // create a String array of 10 objects Array = array. newInstance (classType, 10); // set the element with the index position of 5 to "hello" Array. set (array, 5, "hello"); // obtain the value of the element whose index position is 5 String s = (String) Array. get (array, 5); System. out. println (s );}

    Public static void main (String args []) {int [] dims = new int [] {5, 10, 15 }; // create a new array with the specified component type and dimension. Object array = Array. newInstance (Integer. TYPE, dims); // retrieves the first row of a three-dimensional Array, which is an array Object arrayObj = array. get (Array, 3); Class
       Cls = arrayObj. getClass (). getComponentType (); System. out. println (cls); // retrieves the 3rd columns of the 5th rows, which is an Array of arrayObj = Array. get (arrayObj, 5); // access the 3rd elements in the 5th columns of the 10th rows and assign them 37Array. setInt (arrayObj, 10, 37); // convert a dynamic array to a normal array: forcibly converted to an array such as int arrayCast [] [] [] = (int [] [] []) array; System. out. println (arrayCast [3] [5] [10]);}
    Why should elementData be declared as a transient variable?
    public class ArrayList
       
         extends AbstractList
        
                 implements List
         
          , RandomAccess, Cloneable, java.io.Serializable{    private static final long serialVersionUID = 8683452581122892189L;     /**     * The array buffer into which the elements of the ArrayList are stored.     * The capacity of the ArrayList is the length of this array buffer.     */    private transient Object[] elementData;
         
        
       

    There are two serialization methods:

    A. Only the Serializable interface is implemented.

    During serialization, The defaultWriteObject method of java. io. ObjectOutputStream is called to serialize the object.

    Note: The fields modified by transient are not serialized.

    B. implements the Serializable interface and provides the writeObject method.

    The writeObject method of this class is called during serialization. Instead of the defaultWriteObject method of java. io. ObjectOutputStream.

    Note: whether the transient-modified field will be serialized depends on writeObject.
    /*** Save the state ofArrayListInstance to a stream (that * is, serialize it). ** @ serialData The length of the array backingArrayList* Instance is emitted (int), followed by all of its elements * (eachObject) In the proper order. */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
       
        

    ArrayList will open up extra space to store data. serialization and deserialization consume more resources. Therefore, the array of ArrayList is declared as transient, implement the write/readObject method by yourself, and only serialize the stored data


    Import java. io. *; public class Box implements Serializable // The object class to be saved must implement the serialization interface serializable {private int width; private int height; public void setWidth (int width) {this. width = width;} public void setHeight (int height) {this. height = height;} public static void main (String [] args) {Box myBox = new Box (); myBox. setWidth (50); myBox. setHeight (30); try {// serialization. FileOutputStream fs = new FileOutputStream ("foo. ser "); ObjectOutputStream OS = new ObjectOutputStream (fs); OS. writeObject (myBox); OS. close ();} catch (Exception ex) {ex. printStackTrace () ;}}// serialization method Public static void seserialize (string filename) throws Exception {// deserialization (read the saved object file) objectInputStream in = new ObjectInputStream (new FileInputStream (filename); Box box = (Box) (in. readbject (); System. out. println (box. toString (); In. closer ();}
    Why serialization? Isn't it in memory?

    ArrayList implements the java. io. Serializable interface. When serialization is required, the writeObjcet and readObject methods can be rewritten to provide their own serialization methods.

    1. What is serialization?

    Simply put, the state of various objects stored in the memory (that is, instance variables, not methods) can be read again. Although you can use your own methods to save object states, Java provides you with a mechanism better than your own to save the object state, that is, serialization.

    2. Under what circumstances should serialization be performed?

    A) when you want to save the object state in memory to a file or database;

    B) when you want to use a socket to transmit objects over the network;

    C) when you want to transmit objects through RMI;

    Summary

    1. Arraylist is implemented based on arrays and is self-increasing.

    2. Non-thread-safe

    3. expansion may be required during insertion, And the size will not be reduced during deletion. If necessary, you can use the trimToSize method to traverse the query during the query. If it is null, it determines whether it is null and returns. If it is not null, use equals to judge and return

     /**     * Returns true if this list contains the specified element.     * More formally, returns true if and only if this list contains     * at least one element e such that     * (o==null ? e==null : o.equals(e)).     *     * @param o element whose presence in this list is to be tested     * @return true if this list contains the specified element     */    public boolean contains(Object o) {    return indexOf(o) >= 0;    }     /**     * Returns the index of the first occurrence of the specified element     * in this list, or -1 if this list does not contain the element.     * More formally, returns the lowest index i such that     * (o==null ? get(i)==null : o.equals(get(i))),     * or -1 if there is no such index.     */    public int indexOf(Object o) {    if (o == null) {        for (int i = 0; i < size; i++)        if (elementData[i]==null)            return i;    } else {        for (int i = 0; i < size; i++)        if (o.equals(elementData[i]))            return i;    }    return -1;    }

    4. allow duplicate and null Elements
















Related Article

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.