Java collection class, analyzing the underlying implementation principle from the source code

overall framework

Java collection overall framework and main interface, abstract class analysis

The underlying implementation and principle of ArrayList

Vector underlying implementation and principle

The underlying implementation and principle of LinkedList

The underlying implementation of HashSet (implemented by HashMap) and principle

The underlying implementation of TreeSet (implemented by TreeMap) and principle

The underlying implementation and principle of HashMap (1.7 array + linked list, 1.8 array + linked list + red-black tree)

The underlying implementation and principle of ConcurrentHashMap (commonly used in concurrent programming)

The underlying implementation and principle of TreeMap

The underlying implementation and principle of LinkedHashMap

The following is a summary of the above article. Some points not covered in the above article will be explained in detail.

The relationship between Set and Map

Set represents an unordered and non-repeatable collection, and Map represents a collection composed of multiple Key-Value pairs. On the surface, there seems to be no relationship between them, but Map can be regarded as an extension of Set. Why do you say that? See this example below:

There is such a method in the Map method, Set<k> keySet(), which means that the keys in the Map can be converted into a Set collection. If the value is regarded as an accessory of the key, or the key-value is regarded as a whole, then the Map collection becomes a Set collection.

The relationship between HashSet and HashMap

HashSet and HashMap have many similarities. For HashSet, the Hash algorithm is used to determine the storage location of elements. For HashMap, the value is regarded as an accessory of the key, and the storage location is determined according to the Hash value of the key.

One thing needs to be explained, it is often heard that collections store objects, which is actually inaccurate. To be precise, what is stored in the collection is actually the reference address or reference variable of the object. The reference address or reference variable points to the actual java object. A java collection is actually a collection of reference variables rather than a collection of java objects.

Through the previous source code analysis, it can be found that HashMap does not consider the content of value too much when storing key-value. It just determines where the key-value pair should be stored in the array based on the key. The bottom layer of HashMap is an Entry[] array, and the key-value constitutes an entry. When an element needs to be added to the HashMap, first determine the location stored in the array according to the hashcode of the key. If the key is null, use a special method to process it and store it in the 0th position of the array. If an element already exists at the current position, traverse the singly linked list. If the two keys are equal, replace the old value with the new value. If the key is not equal, insert it into the linked list. One thing to note, before jdk8, hashmap used array + singly linked list storage, after 8, it used array + linked list + red-black tree storage.

There is not much to say about HashSet. The implementation of HashSet is relatively simple. Its bottom layer is implemented using HashMap, but it only encapsulates a HashMap object to store all collection objects.

The relationship between TreeSet and TreeMap

The bottom layer of TreeSet uses a NavigableMap to save the elements of the TreeSet collection, but in fact NavigableMap is just an excuse, because the bottom layer still uses TreeMap to contain the elements in the Set collection. Similar to HashSet, TreeSet also calls methods of TreeMap to implement some operations. The bottom layer of TreeMap is to use the sorted binary tree of "red-black tree" to save each Entry in the Map. The implementation of TreeMap is explained in detail in the above link, please check it yourself.

HashSet and HashMap are unordered while TreeSet and TreeMap are ordered

The relationship between ArrayList and LinkedList

List represents a linear structure, ArrayList is a linear list of sequential storage, the bottom layer of ArrayList uses an array to store each element, and LinkedList is a linear list of chain storage, which is essentially a doubly linked list.

Iterator Iterator

fast-fail fast fail mechanism

During the iteration, if an element is deleted, the collection will throw ConcurrentModificationException.

Why does this exception occur?
This is because during iteration, a thread makes structural changes to the collection, resulting in fail-fast. This exception is thrown when the method detects object modification, but does not allow such modification. fail-fast is just an anomaly detection mechanism, and the JDK does not guarantee that this mechanism will happen.

Through a demo to explain in detail:

LinkedList<String> list = new LinkedList<String>();
list.add("a");
list.add("b");
list.add("c");
list.add("d");

for (String a : list) {
    System.out.println(a);
    list.remove(2);
}

Executing the above code will throw java.util.ConcurrentModificationException; take a
look at the source code of the LinkedList remove() method:

//删除方法
 public E remove(int index) {
        checkElementIndex(index); //验证index是否合法
        return unlink(node(index)); //调用unlink方法
    }
 E unlink(Node<E> x) {
        // assert x != null;
        final E element = x.item;
        final Node<E> next = x.next;
        final Node<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++;   //modCount+1 敲黑板划重点
        return element;
    }

Please refer to the above article for the specific meaning of the above code. The above code will execute the next() method in the private inner class ListItr after deleting the element at the specified position to traverse the next element.

//在私有内部类ListItr中有如下的属性定义,再进行遍历时,将遍历对象的modCount值赋值给了expectedModCount。
private int expectedModCount = modCount;

public E next() {
     checkForComodification();
     if (!hasNext())
         throw new NoSuchElementException();

      lastReturned = next;
      next = next.next;
      nextIndex++;
      return lastReturned.item;
}
final void checkForComodification() {
       if (modCount != expectedModCount)
              throw new ConcurrentModificationException();
 }

After running the next() method, the checkForCommodification() method will be executed first to determine whether modCount and expectedModCount are equal, and an exception will be thrown if they are not equal.

Because it is the modCount value that is unilaterally changed by the traversal object, ListItr does not detect it, so it turns into a situation where modCount and expectedModCount are not equal. So an exception occurred. My understanding is that when using an iterator for object traversal, a new reference is created, and the new reference points to the traversed object, and some properties of the traversed object are assigned to the iterator object. When the method of traversing the object is called, the properties of the object are changed, and the copy of the traversing object in the iterator object can only be updated, resulting in a mismatch of values, thus throwing an exception. This is just my personal understanding, and in-depth exchanges are welcome.

Using the following method, this exception will not occur, because the iterator object has updated its properties! After deletion by the Iterator method, the unity of modCount and expectedModCount values ​​is guaranteed.

Iterator<String> iterator = list.iterator();
        while(iterator.hasNext()){
            String str = iterator.next();
            if(str.equals("a")){
                iterator.remove();
            }
        }

 

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325149187&siteId=291194637