Java Collection ArrayList deep understanding

Source: Internet
Author: User
Tags addall arrays int size concurrentmodificationexception


ArrayList is an implementation class of the list interface in the Java collection framework.

It can be said that ArrayList is the List collection we use most, it has the following characteristics:

Capacity is not fixed, how much you want to put (of course, the maximum threshold, but generally not reach)
Ordered (element output order is consistent with input order)
Element can be null
High efficiency
Size (), IsEmpty (), Get (), set () iterator (), Listiterator () method has a time complexity of O (1)
Add () The average time complexity for adding operations is O (n)
The time complexity of all other operations is almost always O (n)
Less space to occupy
Compare LinkedList to maintain the list structure without taking up extra space
So why do ArrayList have these advantages? We parse through source one by one.

Member variables for ArrayList


1. Underlying data structure, arrays:

Transient object[] Elementdata
Allows NULL to be added because the array type is Object.

Transient indicates that the array cannot be serialized.

The initial time is defaultcapacity_empty_elementdata.

2. Default empty array:

private static final object[] Defaultcapacity_empty_elementdata = {};

private static final object[] Empty_elementdata = {};
It's not clear what the difference is.

3. The initial size of the array is 10:

private static final int default_capacity = 10;
4. Number of current elements in array:

private int size;
Size <= capacity

5. Maximum size of the array:

private static final int max_array_size = integer.max_value-8;
Integer.max_value = 0x7fffffff

Converted into binary: 2^31-1,1111111111111111111111111111111

Decimal is: 2147483647, more than 2.1 billion.

Some virtual players need to add a head tag to the array, so subtract 8.

When you want to allocate a larger number than Max_array_size will be reported OutOfMemoryError.

The key method of ArrayList

1. Constructor function

ArrayList has three constructors:

Initial is an empty array
Public ArrayList () {
This.elementdata = Defaultcapacity_empty_elementdata;
}

//To create an array of objects
public ArrayList (int initialcapacity) {
    if (initialcapacity > 0) {
Based on the specified capacity)         this.elementdata = new Object[initialcapacity];
   } else if (initialcapacity = 0) {
        This.elementdata = Empty_elementdata;
   } else {
        throw new IllegalArgumentException (" Illegal Capacity: "+
                                             initialcapacity);
   }
}

//ArrayList
Public ArrayList (collection<? extends e> c) {
   ) that directly creates and specifies the same content as a collection Elementdata = C.toarray ();
    if ((size = elementdata.length)!= 0) {
       //C.toarr Ay may not return an Object array
        if (Elementdata.getclass ()!= object[].class)
           //Use the Arrays.copy method to create an Object array
             elementdata = arrays.copyof (elementdata, size, object[ ].class);
   } else {
       /Replace with empty array.
&NBSP;&N bsp;      this.elementdata = Empty_elementdata;
   }
}
2. Add element:

Public boolean Add (E e) {
Adjust the capacity of an array
Ensurecapacityinternal (size + 1); Increments modcount!!
elementdata[size++] = e;
return true;
}

Adds an element to the specified location
public void Add (int index, E element) {
Rangecheckforadd (index);

Adjust the capacity of an array
Ensurecapacityinternal (size + 1); Increments modcount!!
It's not very efficient to move the whole back one position.
System.arraycopy (Elementdata, index, Elementdata, index + 1,
Size-index);
Elementdata[index] = element;
size++;
}


Add a Collection
public boolean addall (collection<? extends e> c) {
Convert the collection to an array of objects
Object[] A = C.toarray ();
int numnew = A.length;
Increase capacity
Ensurecapacityinternal (size + numnew); Increments Modcount
Migrate backwards and forwards
System.arraycopy (A, 0, elementdata, size, numnew);
Size + = Numnew;
Returns true if the new array has elements
return numnew!= 0;
}

At the specified location, add a collection
public boolean addall (int index, COLLECTION<? extends e> c) {
Rangecheckforadd (index);

Object[] A = C.toarray ();
int numnew = A.length;
Ensurecapacityinternal (size + numnew); Increments Modcount

int nummoved = Size-index;
The original array migrates backwards and forwards
if (nummoved > 0)
System.arraycopy (Elementdata, index, elementdata, index + numnew,
nummoved);
Adds a new collection array to the specified location
System.arraycopy (A, 0, Elementdata, index, numnew);
Size + = Numnew;
return numnew!= 0;
}
Although System.arraycopy is the underlying method, it is not good to move one at a time after each addition.

3. Adjust the capacity of the array:

public void ensurecapacity (int mincapacity) {
int minexpand = (elementdata!= defaultcapacity_empty_elementdata)
is not the default array, indicating that the element has been added
? 0
The default capacity
: default_capacity;

if (Mincapacity > Minexpand) {
The current number of elements is larger than the default capacity
Ensureexplicitcapacity (mincapacity);
}
}

private void ensurecapacityinternal (int mincapacity) {
Element not yet added
if (Elementdata = = Defaultcapacity_empty_elementdata) {
Minimum capacity default capacity and maximum number of current elements
mincapacity = Math.max (default_capacity, mincapacity);
}

Ensureexplicitcapacity (mincapacity);
}

private void ensureexplicitcapacity (int mincapacity) {
modcount++;

Capacity not enough, need to enlarge
if (Mincapacity-elementdata.length > 0)
Grow (mincapacity);
}
We can actively call ensurecapcity to increase the capacity of the ArrayList object, so as to avoid the addition of the element when full expansion, replication after the consumption.

4. Expansion:

private void Grow (int mincapacity) {
int oldcapacity = Elementdata.length;
1.5 times times the original capacity
int newcapacity = oldcapacity + (oldcapacity >> 1);

If the current capacity is not up to 1.5 times times the old capacity, use the current capacity, provincial station so many places
if (newcapacity-mincapacity < 0)
newcapacity = mincapacity;

The new capacity is beyond the max_array_size.
if (newcapacity-max_array_size > 0)
The maximum capacity can be integer.max_value
newcapacity = hugecapacity (mincapacity);

Mincapacity is generally similar to the number of elements, so the new array size is newcapacity more relaxed
Elementdata = arrays.copyof (Elementdata, newcapacity);
}

private static int hugecapacity (int mincapacity) {
if (mincapacity < 0)//Overflow
throw new OutOfMemoryError ();
Return (Mincapacity > Max_array_size)?
Integer.max_value:
Max_array_size;
}
5. Query, modify and other operations, directly according to the angle of the array of operations, are very fast:

E elementdata (int index) {
Return (E) Elementdata[index];
}

Get
Public E get (int index) {
Rangecheck (index);
Returns the element directly based on the array's angle, faster than the
Return Elementdata (index);
}

Modify
Public E Set (int index, E element) {
Rangecheck (index);
E OldValue = elementdata (index);

Direct array Operations
Elementdata[index] = element;
Return the original value
return oldValue;
}
6. Delete, or a bit slow:

Delete by location
Public E-Remove (int index) {
Rangecheck (index);

modcount++;
E OldValue = elementdata (index);

Move forward one at a
int nummoved = size-index-1;
if (nummoved > 0)
System.arraycopy (Elementdata, index+1, Elementdata, Index,
nummoved);
The last element in the original array is deleted
Elementdata[--size] = null; Clear to let GC does its work

return oldValue;
}

Delete an element
public boolean remove (Object o) {
if (o = = null) {
Traverse to find the target
for (int index = 0; index < size; index++)
if (elementdata[index] = = null) {
Quick Delete
Fastremove (index);
return true;
}
} else {
for (int index = 0; index < size; index++)
if (O.equals (Elementdata[index])) {
Fastremove (index);
return true;
}
}
return false;
}

The internal method, "quick Delete", is to move the duplicate code into a method
I don't see where it's faster than the other remove.
private void Fastremove (int index) {
modcount++;
int nummoved = size-index-1;
if (nummoved > 0)
System.arraycopy (Elementdata, index+1, Elementdata, Index,
nummoved);
Elementdata[--size] = null; Clear to let GC does its work
}

Keep the public
public boolean Retainall (collection<?> c) {
Objects.requirenonnull (c);
Return Batchremove (c, true);
}

Deletes or preserves the elements in the specified collection
Private Boolean Batchremove (Collection<?> C, Boolean complement) {
Final object[] Elementdata = this.elementdata;
Using two variables, one is responsible for backward scanning, one starting from 0, waiting for overwrite operation
int r = 0, w = 0;
Boolean modified = false;
try {
Traverse ArrayList Collection
for (; r < size; r++)
If you specify whether this element is in the collection, determine whether to overwrite it forward according to complement
if (C.contains (elementdata[r]) = = complement)
elementdata[w++] = Elementdata[r];
finally {
An exception was made and the R is copied directly behind the W
if (r!= size) {
System.arraycopy (Elementdata, R,
Elementdata, W,
SIZE-R);
W + + size-r;
}
if (w!= size) {
Clears redundant elements, clear to let GC does its work
for (int i = w; i < size; i++)
Elementdata[i] = null;
Modcount + = size-w;
size = W;
Modified = true;
}
}
return modified;
}

Clear All
public void Clear () {
modcount++;
Does not point the array directly to NULL, but rather to empty the element individually
The next time you use it, you don't have to go new.
for (int i = 0; i < size; i++)
Elementdata[i] = null;

size = 0;
}
7. State of Judgment:

Public Boolean contains (Object o) {
return IndexOf (O) >= 0;
}

//traversal, first found on return
public int indexOf (Object o) {
    if (o = = null) {
&NBSP;&NBSP;&NBSP;&NBSP;&N bsp;   for (int i = 0; i < size; i++)
             if (elementdata[i]==null)
                 return i;
   } else {
        for (int i = 0; i < size; i++)
&nbs p;           if (o.equals (elementdata[i))
                 return i;
   }
    return-1;
}

Walk backwards.
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]))
return i;
}
return-1;
}
8. Convert the array:

Public object[] ToArray () {
Return arrays.copyof (elementdata, size);
}

Public <T> t[] ToArray (t[] a) {
   //If you want to convert only a subset of the groups
    if (A.length < Size)
       //Make a new array of an ' s runtime type, but my contents:
         return (t[]) arrays.copyof (elementdata, size, A.getclass ());
   //All elements copied to array a
    system.arraycopy (elementdata, 0, a, 0, size);
 &nb sp;  if (a.length > Size)
        a[size] = null;
    return A;
}
Look at the arrays.copyof () method:

public static <T,U> t[] copyof (u[] original, int newlength, class<? extends t[]> NewType) {
@SuppressWarnings ("Unchecked")
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;
}
If the NewType is an object pair, the original elements are copied directly into the object array;

Otherwise, create a new array of newType types.

Internal implementation of ArrayList

1. Iterator iterator, listiterator nothing special, directly using the angle to access the elements of the array:

Private class Listitr extends Itr implements listiterator<e> {
LISTITR (int index) {
Super ();
cursor = index;
}

public Boolean hasprevious () {
return cursor!= 0;
}

public int Nextindex () {
return cursor;
}

public int Previousindex () {
return cursor-1;
}

    @SuppressWarnings ("unchecked")
    public E Previous () {
         checkforcomodification ();
        int i = cursor-1;
        if (i < 0)
             throw new Nosuchelementexception ();
        object[] elementdata = ArrayList.this.elementData;
        if (i >= elementdata.length)
             throw new Concurrentmodificationexception ();
        cursor = i;
        return (E) Elementdata[lastret = i];
   }

public void Set (E e) {
if (Lastret < 0)
throw new IllegalStateException ();
Checkforcomodification ();

try {
ArrayList.this.set (Lastret, E);
catch (Indexoutofboundsexception ex) {
throw new Concurrentmodificationexception ();
}
}

public void Add (e e) {
Checkforcomodification ();

try {
int i = cursor;
ArrayList.this.add (i, E);
cursor = i + 1;
Lastret =-1;
Expectedmodcount = Modcount;
catch (Indexoutofboundsexception ex) {
throw new Concurrentmodificationexception ();
}
}
}
In the Java collection in-depth understanding: Abstractlist We introduced the randomaccess, which mentioned that support randomaccess objects, traversal of the use of get than iterators faster.

Because ArrayList inherits from Randomaccess, and its iterators are based on ArrayList methods and arrays of direct operations, the efficiency of get is >= iterator.

int i=0, n=list.size (); I < n; i++)
List.get (i);
Faster than with iterators:

For (iterator I=list.iterator (); I.hasnext ();)
I.next ();
In addition, because ArrayList is not synchronized, when concurrent access, if another thread modifies ArrayList at the same time as the iteration, the Fail-fast iterator Iterator/listiterator reports Concurrentmodificationexception wrong.

Therefore, we need to add a synchronous lock to the ArrayList in the concurrent environment, or to wrap it directly in the initialization with the Collections.synchronizedlist method:

List List = Collections.synchronizedlist (new ArrayList (...));

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.