Java Collection source code analysis (2) ArrayList, javaarraylist

Source: Internet
Author: User
Tags addall

Java Collection source code analysis (2) ArrayList, javaarraylist
ArrayList Overview

ArrayList is implemented based on arrays. It is a dynamic array with its capacity Automatically increasing. It is similar to dynamic memory application in C language and dynamic memory growth.

ArrayList is NOT thread-safe and can only be used in a single-threaded environment. Collections can be used in a multi-threaded environment. the synchronizedList (List l) function returns a thread-safe ArrayList class. You can also use the CopyOnWriteArrayList class under the concurrent package.

ArrayList implements the Serializable interface. Therefore, it supports serialization and implements the RandomAccess interface through serialization and transmission. It supports fast random access. In fact, it uses subscript numbers for fast access and implements the Cloneable interface, can be cloned.

ArrayList source code

The source code of ArrayList is as follows (a simple comment is added, and the version is 1.56 ):

/** @ (#) ArrayList. java 1.56 06/04/21 * Copyright 2006 Sun Microsystems, Inc. all rights reserved. * sun proprietary/CONFIDENTIAL. use is subject to license terms. */package java. util;/*** @ author Josh Bloch * @ author Neal Gafter * @ version 1.56, 04/21/06 * @ see Collection * @ see List * @ see collections List * @ see Vector * @ since 1.2 */public class ArrayList <E> extends actlist <E> implements List <E >, RandomAccess, Cloneable, java. io. serializable {private static final long serialVersionUID = 8683452584252892189l; // ArrayList is implemented based on this array. Use this array to save private transient Object [] elementData; // the actual size of private int size; // Capacity-sized constructor public ArrayList (int initialCapacity) {super (); if (initialCapacity <0) throw new IllegalArgumentException ("Illegal Capacity:" + initialCapacity); this. elementData = new Object [InitialCapacity] ;}// default constructor public ArrayList () {this (10) ;}// Collection constructor 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) ;}// the current capacity value is the actual number of public void trimToSize () {modCount ++; int oldCapacity = elementData. length; if (size <oldCapacity) {elementData = Arrays. copyOf (elementData, size) ;}// determine the ArrayList capacity. // if the capacity is insufficient to accommodate all the current elements, scale up. The new capacity is equal to "(original capacity x3) /2 + 1 "public void ensureCapacity (int minCapacity) {modCount ++; int oldCapacity = elementData. lengt H; 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) ;}// returns the actual public int size () {return size ;}// clear public boolean isEmpty () {return size = 0 ;} // whether o public bool is included Ean contains (Object o) {return indexOf (o)> = 0;} // forward lookup, returns the index public int indexOf (Object o) of 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;} // reverse query, returns the index public int lastIndexOf (Object o) of 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]) return I;} return-1;} // clone function public Object clone () {try {ArrayList <E> v = (ArrayList <E>) super. clone (); v. elementData = Arrays. copyOf (elementData, size); v. modCount = 0; return v;} catch (CloneNotSupportedException e) {// this shouldn't happen, since we are Cloneable throw new InternalError () ;}/// return Ob of ArrayList Ject array public Object [] toArray () {return Arrays. copyOf (elementData, size);} // returns the public <T> T [] toArray (T [] a) {if (. length <size) // Make a new array of a's runtime type, but my contents: return (T []) Arrays. copyOf (elementData, size,. getClass (); System. arraycopy (elementData, 0, a, 0, size); if (. length> size) a [size] = null; return a;} // Positional Access Operations // Public E get (int index) {RangeCheck (index); return (E) elementData [index];} // insert element public E set (int index, E element) {RangeCheck (index); E oldValue = (E) elementData [index]; elementData [index] = element; return oldValue;} // add e public boolean add (E e) {ensureCapacity (size + 1); // Increments modCount !! ElementData [size ++] = e; return true;} // insert element public void add (int index, E element) to index) {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 ++ ;} // remove the 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 workreturn old Value ;}// remove o public boolean remove (Object o) {if (o = null) {for (int index = 0; index <size; index ++) if (elementData [index] = null) {fastRemove (index); return true ;}} else {for (int index = 0; index <size; index ++) if (o. equals (elementData [index]) {fastRemove (index); return true ;}return false ;}// you can quickly remove the private void fastRemove (int index) element from the index position) {modCount ++; int numMoved = size- Index-1; if (numMoved> 0) System. arraycopy (elementData, index + 1, elementData, index, numMoved); elementData [-- size] = null; // Let gc do its work} // clear public void clear () {modCount ++; // Let gc do its workfor (int I = 0; I <size; I ++) elementData [I] = null; size = 0 ;} // Add Collection public boolean addAll (Collection <? Extends E> c) {Object [] a = c. toArray (); int numNew =. length; ensureCapacity (size + numNew); // Increments modCount System. arraycopy (a, 0, elementData, size, numNew); size + = numNew; return numNew! = 0;} // Add Collection public boolean addAll (int index, Collection <? Extends E> c) {if (index> size | index <0) throw new IndexOutOfBoundsException ("Index:" + index + ", Size:" + size ); object [] a = c. toArray (); int numNew =. length; ensureCapacity (size + numNew); // Increments modCountint numMoved = size-index; if (numMoved> 0) System. arraycopy (elementData, index, elementData, index + numNew, numMoved); System. arraycopy (a, 0, elementData, index, numNew); size + = NumNew; return numNew! = 0;} // remove all elements from fromIndex to toIndex protected void removeRange (int fromIndex, int toIndex) {modCount ++; int numMoved = size-toIndex; System. arraycopy (elementData, toIndex, elementData, fromIndex, numMoved); // Let gc do its workint newSize = size-(toIndex-fromIndex); while (size! = NewSize) elementData [-- size] = null;} // removes the private void RangeCheck (int index) {if (index> = size) element at the index position) throw new IndexOutOfBoundsException ("Index:" + index + ", Size:" + size);} // java. io. the Serializable write function writes the "capacity, all element values" of the ArrayList to the private void writeObject (java. io. objectOutputStream s) throws java. io. IOException {// Write out element count, and any hidden stuffint expectedModCount = modC Ount; 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 () ;}// java. io. serializable READ function: reads the "capacity" of the ArrayList according to the write method, and then reads the "All element values" from the private void readObject (java. io. objectInputStream s) throws java. io. IOException, ClassNotFoundException {// Read in size, and any hidden stuffs. defaultReadObject (); // Read in array length and allocate array int arrayLength = s. readInt (); Object [] a = elementData = new Object [arrayLength]; // Read in all elements in the proper order. for (int I = 0; I <size; I ++) a [I] = s. readObject ();}}

 

ArrayList detailed analysis 1. Constructor

ArrayList has three constructors ):

    private transient Object[] elementData;    private int size;    public ArrayList(int initialCapacity) {super();        if (initialCapacity < 0)            throw new IllegalArgumentException("Illegal Capacity: "+                                               initialCapacity);this.elementData = new Object[initialCapacity];    }    public ArrayList() {this(10);    }    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);    }

From the first sentence, we can see that ArrayList is essentially an array of the Object type. The transient keyword is added before, which is ignored during serialization, however, the writeObject and readObject functions are overwritten at the end. The first one is to construct the input ArrayList with a fixed size, and the second one is to set the default size to 10, the third is to convert the imported Collection into an ArrayList.

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.

2. automatic resizing Function
    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);}    }

The key here is int newCapacity = (oldCapacity * 3)/2 + 1; the new array size is 3/2 plus one of the old array size, and then calls Arrays. copyOf (elementData, newCapacity); get the new elementData object. Speaking of this, I silently reviewed the jdk1.7 source code and found that in jdk1.7, the expansion efficiency has been substantially improved. Please refer to the following code: (from jdk1.7)

    public void ensureCapacity(int minCapacity) {        if (minCapacity > 0)            ensureCapacityInternal(minCapacity);    }    private void ensureCapacityInternal(int minCapacity) {        modCount++;        // overflow-conscious code        if (minCapacity - elementData.length > 0)            grow(minCapacity);    }    private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;    private void grow(int minCapacity) {        // overflow-conscious code        int oldCapacity = elementData.length;        int newCapacity = oldCapacity + (oldCapacity >> 1);        if (newCapacity - minCapacity < 0)            newCapacity = minCapacity;        if (newCapacity - MAX_ARRAY_SIZE > 0)            newCapacity = hugeCapacity(minCapacity);        // minCapacity is usually close to size, so this is a win:        elementData = Arrays.copyOf(elementData, newCapacity);    }

1.7 compared with 1.6, automatic resizing adds two methods to the array resizing judgment. The most important thing is: int newCapacity = oldCapacity + (oldCapacity> 1 ); instead of using the low-end method of * 3 and then/2, I directly used the shift operation. I don't know much about the shift operation of the decimal number. After several tests, I found that if it is an even number, this shift operation is exactly half. If it is an odd number, it is rounded down.

 

3. 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 <? Extends E> c), addAll (int index, Collection <? Extends E> c) methods for adding elements.

3.1. set (int index, E element), replace, instead of insert, return the replaced element
    public E set(int index, E element) {RangeCheck(index);E oldValue = (E) elementData[index];elementData[index] = element;return oldValue;    }
3.2.add (E e) adds elements to the end. If the size does not overflow, it will automatically increase.
    public boolean add(E e) {ensureCapacity(size + 1);  // Increments modCount!!elementData[size++] = e;return true;    }
3.3.add (int index, E element) adds an element to a certain position, and all the elements after the index are removed by one
    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++;    }
. The next two methods are to convert the set into an Array Using c. toArray, and then use the Arrays. copyOF method.
    public boolean addAll(Collection<? extends E> 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;    }    public boolean addAll(int index, Collection<? extends E> c) {if (index > size || index < 0)    throw new IndexOutOfBoundsException("Index: " + index + ", Size: " + size);Object[] a = c.toArray();int numNew = a.length;ensureCapacity(size + numNew);  // Increments modCountint numMoved = size - index;if (numMoved > 0)    System.arraycopy(elementData, index, elementData, index + numNew,     numMoved);        System.arraycopy(a, 0, elementData, index, numNew);size += numNew;return numNew != 0;    }
4. 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.

 

    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 workreturn oldValue;    }
5. Arrays. copyOf

The source code is as follows:

    public static <T,U> T[] copyOf(U[] original, int newLength, Class<? extends T[]> 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;    }

It is optimized here. For the Object type, the new Object Array is used. If not, the Array type is generated using the Array. newInstance (newType. getComponentType (), newLength) method. Array replication is implemented through System. arraycopy. System is a final class, And arraycopy is a native method.

This method is marked as native and calls the C/C ++ code of the system. It cannot be seen in JDK, but its source code can be seen in openJDK. This function actually calls the memmove () function in C language. Therefore, it ensures that elements in the same number of groups are correctly copied and moved, which is much more efficient than the general replication method, it is suitable for batch processing arrays. Java strongly recommends this method when copying a large number of array elements to achieve higher efficiency.

6. Significance of Arrays. newInstance ()

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;

7. Why serialization?

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;

8. summary 8.1.Arraylist is based on Array Implementation and is self-increasing 8. 2. non-thread-Safe 8. 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 <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>e</tt> such that     * <tt>(o==null ? e==null : o.equals(e))</tt>.     *     * @param o element whose presence in this list is to be tested     * @return <tt>true</tt> 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 <tt>i</tt> such that     * <tt>(o==null ? get(i)==null : o.equals(get(i)))</tt>,     * 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;    }
8.4. allow duplicate and null Elements

------------------------------------------------------------

References:

[Java Collection source code analysis] ArrayList source code analysis

Arraylist source code analysis for set learning

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.