Brief introduction
The top-most interface in the Java collection is the connection interface, where two interfaces implement the connection interface, respectively, the set interface and the list interface. The set interface behaves unordered, cannot be duplicated, and the list interface behaves as ordered and repeatable. Among them, ArrayList and LinkedList are the most commonly used two in the implementation class of the list interface. Here are some instructions for the two implementation classes ArrayList and LinkedList:
(1) arraylist:arraylist is a generic class with an array structure to hold objects in the bottom layer. The advantage of the array structure is that it facilitates quick random access to the collection, that is, if the objects in the collection need to be accessed frequently from an indexed location, it is more efficient to use the list collection implemented by the ArrayList class. The disadvantage of the array structure is that inserting the object at the specified index and deleting the specified index location object is slower, and the smaller the index position of the inserted or deleted object is less efficient because when an object is inserted at the specified index position, the specified index position and all subsequent objects are moved backwards one at a time.
(2) linkedlist:linkedlist is a generic class, the underlying is a doubly linked list, so it performs insert and delete operations more efficient than ArrayList, but also because of the data structure of the linked list, so the random access is worse than ArrayList. In addition, LinkedList provides a number of methods that can be used as stacks, queues, and double-ended queues.
Internal implementation
ArrayList Internal implementation:
The ArrayList, the storage structure-field and feature implementation-methods, are analyzed in two ways.
Storage Structure-Fields
In terms of structure implementation, ArrayList is an array implementation. First from the source to see
/** * Default initial capacity. */ Private Static Final intDefault_capacity =Ten;/** * Shared empty array instance used for empty instances. */ Private Static FinalObject[] Empty_elementdata = {};/** * GKFX empty array instance used for default sized empty instances. We * Distinguish the empty_elementdata to know what much to inflate when * first element is added. */ Private Static FinalObject[] Defaultcapacity_empty_elementdata = {};/** * The array buffer into which the elements of the ArrayList is stored. * The capacity of the ArrayList is the length of this array buffer. any * empty ArrayList with elementdata = = Defaultcapacity_empty_elementdata * 'll be a expanded to default_capacity When the first element is added. */ transientObject[] Elementdata;//Non-private to simplify nested class access /** * The size of the ArrayList (the number of elements it contains). * * @serial * * Private intSize
An array of type object is maintained in ArrayList Elementdata, which is used to hold data. Note that this array is the transient type, and this is left below. Next ArrayList The default size is 10. Where size is the number of elements in the current array. The remaining two parameters are used to initialize the Elementdata array.
Function Implementation-method
ArrayList function mainly includes adding and removing changes, as well as expanding operation. Here the main expansion operation, the Add method to expand the analysis.
1. Expansion operation
Expansion is the recalculation of capacity, want to ArrayList objects constantly add elements, and ArrayList objects inside the array cannot load more elements, the object needs to enlarge the length of the array, so that more elements can be loaded. Arrays in Java cannot be automatically expanded by using a new array instead of an existing array of small size. ArrayList's expansion entry function is ensurecapacity and ENSURECAPACITYINTERNAL,JAVA8 source code as follows:
/** * Increases the capacity of this <tt>ArrayList</tt> instance, if * necessary, to ensure that I T can hold at least the number of elements * specified by the minimum capacity argument. * * @param mincapacity the desired minimum capacity * * Public void ensurecapacity(intmincapacity) {intMinexpand = (Elementdata! = defaultcapacity_empty_elementdata)//Any size if not default element table?0 //Larger than default for default empty table. It ' s already //Supposed to is at default size.: default_capacity;if(Mincapacity > Minexpand) {ensureexplicitcapacity (mincapacity); } }Private void ensurecapacityinternal(intmincapacity) {if(Elementdata = = Defaultcapacity_empty_elementdata) {mincapacity = Math.max (default_capacity, mincapacity); } ensureexplicitcapacity (mincapacity); }Private void ensureexplicitcapacity(intmincapacity) {modcount++;//Overflow-conscious code if(Mincapacity-elementdata.length >0) grow (mincapacity); }
Java8 the code in the JAVA7 has a small amplitude change, the first entry function will be called to ensureexplicitcapacity () This method, Modcount generally appear in the iterator, here is the record list structure has been changed the number of times. You can see that the Grow method is called only when the mincapacity is larger than the current array length, and then the Grow method:
/** * Increases the capacity to ensure so it can hold at least the * number of elements specified by the min Imum capacity argument. * * @param mincapacity the desired minimum capacity * * Private void Grow(intmincapacity) {//Overflow-conscious code intoldcapacity = Elementdata.length;intNewcapacity = 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); }
这里便于java7有点区别了,java7中的capacity计算如下:
The mathematical formula used in the JAVA7, while the JAVA8 uses the displacement operation, moves one after another to the same size as the array in the Java7, and the displacement operation is much faster than the mathematical formula. After the newcapacity is determined, the Arrays.copy method is called to generate a new array of arrays.
2.add operation
The add operation is to insert a new piece of data into the ArrayList object, as follows:
/** * Appends the specified element to the end of this list. * * @param e element to being appended to the This list * @return <tt>true</tt> (as Specifi Ed by {@link Collection#add}) * / Public Boolean Add(e) {ensurecapacityinternal (size +1);//increments modcount!!elementdata[size++] = e;return true; }/** * Inserts the specified element at the specified position in this * list. Shifts the element currently at, if any, and * any subsequent elements to the right (adds one to their I ndices). * * @param Index index at which the specified element was to be inserted * @param element element To be inserted * @throws indexoutofboundsexception {@inheritDoc} */ Public void Add(intIndex, E Element) {Rangecheckforadd (index); Ensurecapacityinternal (size +1);//increments modcount!!System.arraycopy (Elementdata, index, elementdata, index +1, Size-index); Elementdata[index] = element; size++; }
Add has two overloaded methods, the first one is to insert the data to the end by default, and the second to specify the insertion position. Two methods will call Ensurecapacityinternal first, and the incoming parameter is size+1, so that the ArrayList array will never exceed the bounds. For the second method, the main call is Arraycopy, the source code is as follows:
It can be seen that this is a local method, the explanation is very clear, ArrayList is the index on the data back one bit.
LinkedList Internal implementation:
transientint0; /** * Pointer to first node. * Invariant: (first == null && last == null) || * (first.prev == null && first.item != null) */ transient Node<E> first; /** * Pointer to last node. * Invariant: (first == null && last == null) || * (last.next == null && last.item != null) */ transient Node<E> last;
The LinkedList, the storage structure-field and feature implementation-methods, are analyzed in two ways.
Storage Structure-Fields
From the structure realization, the LinkedList is the bidirectional linked list realization. First from the source to see
There is a bit of a change compared to JAVA7, where size is used to represent the number of objects in the current object, First,last points to the head node and the tail node respectively. Note that it is stated that for the transient type, this is explained in the next article. Node internal class source code is as follows:
privatestaticclass Node<E> { E item; Node<E> next; Node<E> prev; Node(Node<E> prev, E element, Node<E> next) { this.item = element; this.next = next; this.prev = prev; } }
It's clear at a glance that item is the current value, and next and Prev point to the next node and the previous node, respectively.
Function Implementation-method
LinkedList function mainly includes adding and removing changes. Because it is the data structure of the linked list, there is no expansion method, here is the main method to add the Remove method into the explanation.
1.add Operation:
/** * Inserts the specified element at the specified position in T His list. * Shifts the element currently at, if any, and any * subsequent elements to the right (adds one to their indices). * * @param index index at which the specified element was to be inserted * @param element element to be inserted * @throws indexoutofboundsexception {@inheritDoc} */ public void add (int Index, E element) {Check Positionindex (index); if (index = = size) linklast (element); else linkbefore (element, node (index)); }
can see that there are three methods of Checkpositionindex, Linklast, Linkbefore, where the Checkpositionindex method is only specified when the index bit is inserted. Used to verify that index is legal (the legal criterion must be greater than 0 is less than or equal to size). If Index==size is then directly inserted at the end of the last pointer, take a look at the node method and the Linkbefore method as follows:
/** * Returns the (non-null) Node at the specified element index. */ node<e> Node (int index) {//as SERT Iselementindex (index); if (Index < (size >> 1 )) {node<e> x = first; for (int i = 0 ; i < index; i++) x = X.nex T return x; } else {node<e> x = last; for (int i = size-1 ; i > Index; i--) x = X.prev; return x; } }
The node method returns the node at the index position based on the index position. Here in order to reduce the number of convenience, if the index is larger than the average size, then the reverse begins to traverse.
/** * Inserts element e before non-null Node succ. */ void linkBefore(E e, Node<E> succ) { // assert succ != null; final Node<E> pred = succ.prev; finalnew Node<>(pred, e, succ); succ.prev = newNode; ifnull) first = newNode; else pred.next = newNode; size++; modCount++; }
Once you've determined the node pointer for the index bit, you just need to change the link list point. Note that the modcount here are also used in iterators.
2.remove Operation:
Public Boolean Remove(Object o) {if(O = =NULL) { for(node<e> x = first; X! =NULL; x = X.next) {if(X.item = =NULL) {unlink (x);return true; } } }Else{ for(node<e> x = first; X! =NULL; x = X.next) {if(O.equals (X.item)) {unlink (x);return true; } } }return false; }
可以看出remove其实只做了两件事,1、检查index是否合法;2、调用unlink方法,传入index位置的node节点;下面我们看看unlink方法:
/** * unlinks non-null node x. */E unlink (node<e> x) {//assert x! = null; FinalE element = X.item;FinalNode<e> next = X.next;Finalnode<e> prev = X.prev;if(prev = =NULL) {first = next; }Else{Prev.next = next; X.prev =NULL; }if(Next = =NULL) {last = prev; }Else{Next.prev = prev; X.next =NULL; } X.item =NULL; size--; modcount++;returnElement }
In fact, is the standard Chat table node Delete operation, it is necessary to be aware of the boundary situation, that is, the head node and the tail node situation.
Transient analysis
Note that some of the variables in ArrayList and LinkedList are decorated with transient keywords. such as the Elementdata array in ArrayList, the pointer to the head node and the tail node in the LinkedList. The following explains the role of the Transient keyword:
Java's serialization provides a mechanism for persisting object instances. When persisting an object, there may be a special object data member, and I do not want to use the serialization mechanism to save it. In order to turn off serialization on a specific object's domain, you can precede the domain with the keyword transient. Transient is a keyword used to indicate that one is not part of the serialization of the object. When an object is serialized, the value of the variable modified by the Transient keyword is not included in the serialized representation, and the non-transient variable is included.
So since the variables used to hold the data are transient decorated, can ArrayList and LinkedList still be serial numbers?
The answer is yes. For ArrayList, if the elementdata is not declared as a transient type, then the data inside the serialization is serialized, but elementdata this array is a large program where there is a null value (that is, the size
Anatomy of ArrayList and LinkedList