What’s the difference between ArrayList and LinkedList?

Personally, I think the answer to this question should be divided into the following parts:

  1. This section describes the underlying implementation of ArrayList

  2. Introduces the underlying implementation of LinkedList

  3. Both are suitable for what occasion

This article is organized along these lines.

ArrayList source code parsing

Member attribute source code parsing

Copy the code
  1. public class ArrayList<E>

  2. extends AbstractList<E>

  3. implements List<E>, RandomAccess

  4. ,Cloneable , java.io.Serializable {

  5. private static final long

  6. serialVersionUID

  7. = 8683452581122892189L ;


  8. // The default capacity is 10

  9. private static final int

  10. DEFAULT_CAPACITY = 10;


  11. // When the ArrayList constructor is passed in with a capacity of 0

  12. // The capacity of the container is 0

  13. private static final Object []

  14. EMPTY_ELEMENTDATA = {};

Pick up the above

Copy the code
  1. / *

  2. It is mainly used as an identifier bit for capacity expansion.

  3. The default size and capacity are 0, used when the default capacity is used

  4. It’s “lazy loading” : waiting until you add elements to actually do it

  5. Allocation of capacity, and we’ll talk about that later in the expansion function

  6. * /

  7. private static final Object[]

  8. DEFAULTCAPACITY_EMPTY_ELEMENTDATA={};


  9. //ArrayList The elements that are stored in the underlying Object array

  10. transient Object[] elementData;


  11. // Records how many elements there are in the current container

  12. private int size;

Constructor source code parsing

Copy the code
  1. / *

  2. One of the most commonly used constructors actually creates one

  3. Specifies the size of the Object array to hold the elements added later

  4. * /

  5. public ArrayList(int initialCapacity){

  6. if (initialCapacity > 0) {

  7. // Initialize the Object array that holds the data

  8. this .elementData

  9. =new Object[initialCapacity];

  10. } else if(initialCapacity==0) {

  11. EMPTY_ELEMENTDATA: void EMPTY_ELEMENTDATA

  12. this .elementData

  13. = EMPTY_ELEMENTDATA;

  14. } else {

  15. throw new

  16. IllegalArgumentException (

  17. "Illegal Capacity: " +

  18. initialCapacity);

  19. }

  20. }


  21. / *

  22. The no-parameter constructor points to an Object of the default size

  23. Array, notice that it does not exist when we use the no-argument constructor

  24. Create an Object of size 10(default: 10)

  25. Arrays instead take the lazy-loading strategy: use

  26. DEFAULTCAPACITY_EMPTY_ELEMENTDATA,

  27. This default array has a capacity of 0, so you have to differentiate between

  28. The default capacity, or the size of the capacity argument you passed to the constructor

  29. It’s 0 itself. It is created when the add operation is actually performed

  30. Object array, that is, there is a default capacity to handle in the capacity expansion function

  31. There will be detailed analysis later.

  32. * /

  33. public ArrayList() {

  34. // This assignment is just for identification purposes

  35. this .elementData =

  36. DEFAULTCAPACITY_EMPTY_ELEMENTDATA;

  37. }


  38. // Omit some uncommon code functions

Add method source code analysis

Copy the code
  1. / *

  2. Add is the most commonly used interface for ArrayList, and the logic is simple

  3. * /

  4. public boolean add(E e) {

  5. / *

  6. It is mainly used to indicate that the thread is safe, that is, an ArrayList can only

  7. When used in a single-threaded environment, concurrency occurs in a multi-threaded environment

  8. ModCount is mainly used to record data against ArrayList

  9. Modify number of times if a thread operates during ArrayList

  10. ModCount has changed meaning that multiple threads are modifying the current at the same time

  11. This ArrayList, that’s going to be thrown

  12. “ConcurrentModificationException” abnormal,

  13. This is also known as the “failFast mechanism” and is common in many non-thread-safe applications

  14. Classes have failFast mechanisms: HashMap, LinkedList

  15. And so on. This mechanism is mainly used for iterators, enforcing for loops, and so on

  16. Function, which is a thread iterating through a failfast mechanism

  17. If another thread changes the elements in the container,

  18. The thread of iteration will throw

  19. “ConcurrentModificationException” exception

  20. * /

  21. modCount++;


  22. / *

  23. The core function of the add operation does not exist when the no-argument constructor is used

  24. Allocate an Object array of size 10 directly, which has the corresponding processing logic.

  25. * /

  26. // Enter the function

  27. add(e, elementData, size);

  28. return true;

  29. }


  30. private void add(E e,Object[] elementData

  31. , int s) {

  32. / *

  33. If using the no-parameter constructor: starts with length 0,

  34. S is also 0. Grow () core function, expansion/initialization operation

  35. * /

  36. if (s == elementData.length)

  37. elementData = grow();

  38. elementData[s] = e;

  39. size = s + 1 ;

  40. }

Grow related method source code parsing

Copy the code
  1. private Object[] grow() {

  2. // Continue tracing

  3. return grow(size + 1);

  4. }


  5. private Object[] grow(int minCapacity){

  6. / *

  7. Using array copy, expand: add elementData

  8. All of the elements are copied into a new array, the new array

  9. The length is the return value of newCapacity(), and then

  10. Assign this new array to elementData to complete the expansion

  11. operation

  12. * /

  13. // Enter newCapacity()

  14. return elementData =

  15. Arrays .copyOf(elementData,

  16. newCapacity(minCapacity));

  17. }


  18. // Returns the size of the expanded array

  19. private int newCapacity(int minCapacity){

  20. int oldCapacity=elementData.length;

  21. // The capacity after expansion is 1.5 times of the original capacity

  22. int newCapacity = oldCapacity

  23. + (oldCapacity >> 1);

  24. if (newCapacity-minCapacity <=0){

  25. if (elementData ==

  26. DEFAULTCAPACITY_EMPTY_ELEMENTDATA)

  27. // Handle the default capacity

  28. return Math.max(

  29. DEFAULT_CAPACITY, minCapacity);


  30. / *

  31. MinCapacity is an int and may overflow

  32. Yes ArrayList the maximum size is integer.max_value

  33. * /

  34. if (minCapacity<0) //overflow

  35. throw new OutOfMemoryError();


  36. // Return the new capacity

  37. return minCapacity;

  38. }


  39. / *

  40. MAX_ARRAY_SIZE=Integer.MAX_VALUE-8,

  41. If the capacity is greater than MAX_ARRAY_SIZE, return

  42. hugeCapacity(minCapacity),

  43. That’s integer.max_value

  44. * /

  45. return (newCapacity-MAX_ARRAY_SIZE

  46. <= 0 )? newCapacity

  47. : hugeCapacity(minCapacity);

  48. }


  49. private static int hugeCapacity

  50. (int minCapacity){

  51. if (minCapacity < 0) // overflow

  52. throw new OutOfMemoryError();

  53. return (minCapacity>MAX_ARRAY_SIZE)

  54. ? Integer .MAX_VALUE

  55. : MAX_ARRAY_SIZE;

  56. }

The failfast mechanism of ArrayList

Copy the code
  1. // Finally, ArrayList failFast

  2. private class Itr implements

  3. Iterator <E>{

  4. //index of next element to return

  5. int cursor;

  6. // index of last element returned;

  7. int lastRet = -1; -1 if no such

  8. / *

  9. Save the modCount value before iterating,

  10. ModCount is changing container elements, containers

  11. It increases in size by 1

  12. * /

  13. int expectedModCount=modCount;


  14. // prevent creating a synthetic

  15. // constructor

  16. Itr () {}


  17. public boolean hasNext() {

  18. return cursor ! = size;

  19. }


  20. @SuppressWarnings ("unchecked")

  21. public E next() {

  22. / *

  23. Check first when iterating through an element

  24. Is modCount equal to the expected value,

  25. Go into that function

  26. * /

  27. checkForComodification();

  28. int i = cursor;

  29. if (i >= size)

  30. throw new

  31. NoSuchElementException ();

  32. Object [] elementData =

  33. ArrayList .this.elementData;

  34. if (i >= elementData.length)

  35. throw new

  36. ConcurrentModificationException ();

  37. cursor = i + 1;

  38. return (E)elementData[lastRet=i];

  39. }


  40. / *

  41. You can see that if a thread changes during an iteration

  42. The container is thrown

  43. “ConcurrentModificationException”

  44. * /

  45. final void checkForComodification(){

  46. if (modCount! =expectedModCount)

  47. throw new

  48. ConcurrentModificationException ();

  49. }

The other operations on an ArrayList, such as get, remove, and indexOf, are simple operations on an Object array: get an element at an index position, delete an element from the array, and find an element at…… So it’s important to understand how it works.

ArrayList (ArrayList) : Initial capacity, maximum capacity, use of an Object array to store elements (similarities and differences between arrays and lists), failFast mechanism, failFast mechanism, etc.

LinkedList source code analysis

Source code analysis of member attributes

Copy the code
  1. public class LinkedList<E>

  2. extends AbstractSequentialList<E>

  3. implements List<E>, Deque<E>

  4. ,Cloneable , java.io.Serializable {

  5. MAX_ARRAY_SIZE= Integer.MAX_VALUE-8,

  6. / *

  7. LinkedList size is of type int, but after

  8. You’ll see that the LinkedList size is really only dependent on memory size

  9. Limit the size of the LinkedList

  10. Overflow occurred, return a negative number

  11. * /

  12. transient int size = 0;


  13. //LinkedList is a two-way list.

  14. // Keep references to the first and last nodes

  15. transient Node

    first; / / head node


  16. transient Node

    last; / / end nodes

  17. // omit some extraneous code


  18. // Let’s analyze the LinkedList inner class Node

Internal class Node source code analysis

Copy the code
  1. private static class Node<E> {

  2. E item; / / element value

  3. Node

    next; // Subsequent nodes


  4. // The precursor Node is a bidirectional list

  5. Node <E> prev;


  6. Node (Node<E> prev, E element

  7. , Node

    next) {//Node constructor

  8. this .item = element;

  9. this .next = next;

  10. this .prev = prev;

  11. }

  12. }

Constructor source code analysis

Copy the code
  1. //LinkedList no parameter constructor: nothing done

  2. public LinkedList() {}

Other core assisted interface method source code analysis

Copy the code
  1. / *

  2. Most of the interface to LinkedList is based on

  3. These interfaces implement:

  4. 1. Insert elements to the head of the list

  5. 2. Insert elements to the end of the list

  6. 3. Insert a node before the specified node

  7. 4. Delete the header of the linked list

  8. 5. Delete the last node of the unlinked list

  9. 6. Delete the specified node from the unlinked list

  10. * /

  11. //1. Insert elements to the head of the list

  12. private void linkFirst(E e) {

  13. final Node<E> f = first;

  14. final Node<E> newNode =

  15. new Node<>(null, e, f);

  16. first = newNode;

  17. if (f == null)

  18. last = newNode;

  19. else

  20. f.prev = newNode;

  21. size++;

  22. modCount++; / / failFast mechanism

  23. }


  24. //2. Insert elements to the end of the list

  25. void linkLast(E e) {

  26. final Node<E> l = last;

  27. final Node<E> newNode =

  28. new Node<>(l, e, null);

  29. last = newNode;

  30. if (l == null)

  31. first = newNode;

  32. else

  33. l.next = newNode;

  34. size++;

  35. modCount++; / / failFast mechanism

  36. }


  37. Insert a node before the specified node (succ)

  38. void linkBefore(E e, Node<E> succ) {

  39. // assert succ ! = null;

  40. final Node<E> pred = succ.prev;

  41. final Node<E> newNode

  42. = new Node<>(pred, e, succ);

  43. succ.prev = newNode;

  44. if (pred == null)

  45. first = newNode;

  46. else

  47. pred.next = newNode;

  48. size++;

  49. modCount++; / / failFast mechanism

  50. }


  51. // delete the header of the linked list

  52. private E unlinkFirst( Node<E> f){

  53. //assert f==first && f! =null;

  54. final E element = f.item;

  55. final Node<E> next = f.next;

  56. f.item = null ;

  57. f.next = null ; //help GC

  58. first = next;

  59. if (next == null)

  60. last = null ;

  61. else

  62. next.prev = null;

  63. size--;

  64. modCount++; / / failFast mechanism

  65. return element;

  66. }


  67. //5. Delete the last node of the unlinked list

  68. private E unlinkLast( Node<E> l) {

  69. //assert l==last && l! =null;

  70. final E element = l.item;

  71. final Node<E> prev = l.prev;

  72. l.item = null ;

  73. l.prev = null ; // help GC

  74. last = prev;

  75. if (prev == null)

  76. first = null ;

  77. else

  78. prev.next = null;

  79. size--;

  80. modCount++; / / failFast mechanism

  81. return element;

  82. }


  83. //6. Delete the specified node in the delete list

  84. E unlink(Node <E> x) {

  85. // assert x ! = null;

  86. final E element = x.item;

  87. final Node<E> next = x.next;

  88. final Node<E> prev = x.prev;


  89. if (prev == null) {

  90. first = next;

  91. } else {

  92. prev.next = next;

  93. x.prev = null ;

  94. }


  95. if (next == null) {

  96. last = prev;

  97. } else {

  98. next.prev = prev;

  99. x.next = null ;

  100. }


  101. x.item = null ;

  102. size--;

  103. modCount++; / / failFast mechanism

  104. return element;

  105. }

Common API source code analysis

Copy the code
  1. Public E removeFirst() {

  2. final Node<E> f = first;

  3. if (f == null)

  4. throw

  5. new NoSuchElementException();

  6. // call 4. Remove the header implementation of the list

  7. return unlinkFirst(f);

  8. }


  9. public E removeLast() {

  10. final Node<E> l = last;

  11. if (l == null)

  12. throw

  13. new NoSuchElementException();

  14. // Call 5. Remove the tail node implementation of the division list

  15. return unlinkLast(l);

  16. }


  17. public void addFirst(E e) {

  18. 1. Insert element implementation to the head of the list

  19. linkFirst(e);

  20. }


  21. public void addLast(E e) {

  22. // Call 2. Insert the element implementation to the end of the list

  23. linkLast(e);

  24. }


  25. public boolean add(E e) {

  26. // Call 2. Insert the element implementation to the end of the list

  27. linkLast(e);

  28. return true;

  29. }


  30. public boolean remove(Object o) {

  31. if (o == null) {

  32. for (Node<E> x = first;

  33. x ! = null ; x = x.next) {

  34. if (x.item == null) {

  35. // call 6. Delete the division list

  36. // Specify the node implementation

  37. unlink(x);

  38. return true;

  39. }

  40. }

  41. } else {

  42. for (Node<E> x = first

  43. ; x ! = null ; x = x.next) {

  44. if (o.equals(x.item)) {

  45. // call 6. Delete the division list

  46. // Specify the node implementation

  47. unlink(x);

  48. return true;

  49. }

  50. }

  51. }

  52. return false;

  53. }


  54. // omit other extraneous functions

Failfast mechanism

Copy the code
  1. // failFast in iterators private class ListItr

  2. implements ListIterator<E> {

  3. private Node<E> lastReturned;

  4. private Node<E> next;

  5. private int nextIndex;


  6. / *

  7. Save the modCount value before iterating,

  8. ModCount changes container elements and container sizes

  9. It increases by 1

  10. * /

  11. private int expectedModCount

  12. = modCount;


  13. ListItr (int index) {

  14. next = (index == size)

  15. ? null : node(index);

  16. nextIndex = index;

  17. }


  18. public boolean hasNext() {

  19. return nextIndex < size;

  20. }


  21. public E next() {

  22. / *

  23. Check first when iterating through an element

  24. Is modCount equal to the expected value,

  25. Go into that function

  26. * /

  27. checkForComodification();

  28. if (! hasNext())

  29. throw

  30. new NoSuchElementException();


  31. lastReturned = next;

  32. next = next.next;

  33. nextIndex++;

  34. return lastReturned.item;

  35. }


  36. / *

  37. You can see that if a thread changes the container during the iteration,

  38. It throws

  39. “ConcurrentModificationException”

  40. * /

  41. final void checkForComodification(){

  42. if (modCount! =expectedModCount)

  43. throw new

  44. ConcurrentModificationException ();

  45. }

The implementation of LinkedList is relatively simple: the bottom layer uses bidirectional LinkedList implementation, retains the first and last two Pointers, and other operations of LinkedList are basically implemented based on the above six functions. In addition, LinkedList also has failFast mechanism, which is mainly used in iterators.

Arrays and linked lists have their own characteristics

The difference between array and linked list is essentially the difference between continuous space storage and discontinuous space storage. There are two main points:

ArrayList: The underlying implementation of Object arrays: Since the addresses of arrays are contiguous, arrays support O(1) random access; The size of the array is specified when it is initialized; Arrays do not support dynamic scaling, and arrays like ArrayList, Vector, and Stack seem to have no capacity concerns (because you can always store data in them). But they’ve actually expanded their base; The cost of array expansion is relatively high, so it is necessary to create a new array to copy data into it, which is inefficient for array expansion. Suitable for scenarios where there is a large amount of data to be read.

LinkedList: The underlying data structure is a Node with two Pointers. Compared with array, linked list insertion efficiency is higher, only need to change the front and back two Pointers; In addition, linked lists do not have the problem of capacity expansion, because linked lists do not require continuous storage space, each insertion of data only changes the last pointer; In addition, linked lists require more memory than arrays because they maintain two Pointers; It is suitable for deleting, inserting more scenes LinkedList and implements the Deque interface.


This article is from “Java Technology Station”, a partner of the cloud community. For more information, you can pay attention to “Java Technology Station”.