# Java collection framework details

Java collection framework details

Collection framework overview map

Insert picture description here

Iterable interface

The Iterable interface is the top-level interface of the Java collection framework. Implementing this interface can traverse its own elements through an iterator. In the Java container, Collection inherits the Iterable interface.

Iterable interface source code

public interface Iterable<T> {
    
    
	// 创建一个类型为T的Iterator的实例
    Iterator<T> iterator();

    // 遍历操作集合内的元素
    default void forEach(Consumer<? super T> action) {
    
    
        Objects.requireNonNull(action);
        for (T t : this) {
    
    
            action.accept(t);
        }
    }
    // 并行遍历元素的迭代器
    default Spliterator<T> spliterator() {
    
    
        return Spliterators.spliteratorUnknownSize(iterator(), 0);
    }
}

Iterator interface

The Iterator interface provides operations on elements such as hasNext() and next(). The implementation of the Iterator class completes the operations of specific elements. The anonymous inner class in the subclass of Collection will implement the Iterator interface to operate on the elements in the container.


Collection interface

The Collection interface defines methods such as element attributes and element methods.

@Test
public void test1(){
    
    

    Collection list = new ArrayList();
    Collection linkList = new LinkedList();
    Collection set = new HashSet();
    Collection linkSet = new LinkedHashSet();
    Collection queue = new ArrayDeque();
    Collection deQueue = new DelayQueue();
}

Inherit the interface of Collection

List

The List interface extends the methods in the Collection interface.


ArrayList
public class ArrayList<E> extends AbstractList<E>        implements List<E>, RandomAccess, Cloneable, java.io.Serializable{
    
    }

Insert picture description here

  • Overview of ArrayList : ArrayList is implemented based on arrays and can be dynamically expanded. ArrayList is not thread-safe, and realizes the
    Serializable interface to be able to serialize transmission. Supports fast random access, and implements the Cloneable interface to implement object cloning.
  • ArrayList initialization
// 默认无参构造函数
public ArrayList() ;
// 制定大小初始化
public ArrayList(int initialCapacity);
// Collection实例初始化
public ArrayList(Collection<? extends E> c)
  • ArrayList dynamic expansion : in add()
// 最具体的扩容方法
private void grow(int minCapacity) {
    
    
    // 目前数组的长度
    int oldCapacity = elementData.length;
    // 新的数组的大小 旧数组大小+就数组大小右移1位
    // newCapacity =oldCapacity + 0.5 * oldCapacity  
    int newCapacity = oldCapacity + (oldCapacity >> 1);
    if (newCapacity - minCapacity < 0)
        newCapacity = minCapacity;
    // MAX_ARRAY_SIZE 为int最大值减去8
    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);
}

If it is constructed with no parameters, the initial array capacity is 0. When the array is actually added, the capacity is actually allocated. Follow oldCapacity + (oldCapacity >> 1) each time. Expansion by means of copeOf.


Set

The Set interface inherits the methods in the Collection extension Collection interface,

HashSet class relationship

Insert picture description here


Java.util.Map interface

HashMap class relationship
public class HashMap<K,V> extends AbstractMap<K,V>    implements Map<K,V>, Cloneable, Serializable {
    
    }

Insert picture description here

HashMap underlying storage structure

HashMap is a collection used to store Key-Value key-value pairs, and each key-value pair is also called an Entry. Both key and value in HashMap can be null.

  • Array : The elements in the array are stored in the form of Entry<K,V>.
/**
  * Basic hash bin node, used for most entries.  (See below for
  * TreeNode subclass, and in LinkedHashMap for its Entry subclass.)
  */
static class Node<K,V> implements Map.Entry<K,V> {
    
    
    // 定位数组索引位置
    final int hash;
    final K key;
    V value;
    // 链表的下一个节点
    Node<K,V> next; 

    Node(int hash, K key, V value, Node<K,V> next) {
    
    
        this.hash = hash;
        this.key = key;
        this.value = value;
        this.next = next;
    }
    public final K getKey()        {
    
     return key; }
    public final V getValue()      {
    
     return value; }
    public final String toString() {
    
     return key + "=" + value; }
    public final int hashCode() {
    
    }
    public final V setValue(V newValue) {
    
    }
    public final boolean equals(Object o) {
    
    }
}
  • Linked list
  • Red-black tree : When the linked list is too long, it is converted to a red-black tree, and when the length of the linked list is too long (the default is more than 8), the linked list is converted to a red-black tree. Use the red-black tree to quickly add, delete, modify and check the characteristics to improve the performance of HashMap. Among them, red-black tree insertion, deletion, and search algorithms are used.
HashMap uses hash table storage
  • Map.put("name","Zhang San")

Call hashCode() to calculate the hash value of name, and locate the storage location of the key-value pair through the high-order operation and modulo operation of the hash algorithm. When the hashCode value of the key is the same, a hash collision occurs. A good hash algorithm and expansion mechanism can reduce the probability of hash collisions.

int threshold;             // 所能容纳的key-value对极限 
final float loadFactor;    // 负载因子
int modCount;  // 记录HashMap内部结构发生变化的次数
int size; // Map中存的键值对数量
  • The initial length of Node[K,V] table[] is 16 , the load factor (default value is 0.75 ), and the threshold is the number of Nodes (key-value pairs) with the maximum amount of data that the HashMap can hold. threshold = length * Load factor . In other words, after the length of the array is defined, the larger the load factor, the more key-value pairs that can be accommodated.
  • Threshold is the maximum number of elements allowed under the corresponding Load factor and length (array length). If this number is exceeded, it will be resized (expanded). The expanded HashMap capacity is twice the previous capacity.
HashMap determines the array index position
  • hashCode index
  • High-order operations
  • Modulo operation: h& (length-1) operation is equivalent to taking the modulo length, which is h%length, but & has higher efficiency than %.
static final int hash(Object key) {
    
    
    int h;
    // 计算key的hash值 h = key.hashCode()
    // 高位参与运算 h^(h>>>16) h异或(h右移16位)
    return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}
Expansion mechanism

Insert picture description here

  • Resize is to recalculate the capacity and add elements to the HashMap object continuously. When the array inside the HashMap object cannot load more elements, the object needs to expand the length of the array so that more elements can be loaded. Of course, the array in Java cannot be automatically expanded. The method is to use a new array to replace the existing array with a small capacity, just like we use a small bucket to store water. If we want to store more water, we have to change the big bucket. .
final Node<K,V>[] resize() {
    
    
    Node<K,V>[] oldTab = table;
    int oldCap = (oldTab == null) ? 0 : oldTab.length;
    int oldThr = threshold;
    int newCap, newThr = 0;
    if (oldCap > 0) {
    
    
         //若容量超过最大值,则无法进行扩容,需扩大阀值
        if (oldCap >= MAXIMUM_CAPACITY) {
    
    
            threshold = Integer.MAX_VALUE;
            return oldTab;
        }
         // 没超过最大值,就扩充为原来的2倍
        else if ((newCap = oldCap << 1) < MAXIMUM_CAPACITY &&
                 oldCap >= DEFAULT_INITIAL_CAPACITY)
            newThr = oldThr << 1; // double threshold
    }
    else if (oldThr > 0) // initial capacity was placed in threshold
        newCap = oldThr;
    else {
    
                   // zero initial threshold signifies using defaults
        newCap = DEFAULT_INITIAL_CAPACITY;
        newThr = (int)(DEFAULT_LOAD_FACTOR * DEFAULT_INITIAL_CAPACITY);
    }
     // 计算新的resize上限
    if (newThr == 0) {
    
    
        float ft = (float)newCap * loadFactor;
        newThr = (newCap < MAXIMUM_CAPACITY && ft < (float)MAXIMUM_CAPACITY ?
                  (int)ft : Integer.MAX_VALUE);
    }
    threshold = newThr;
    @SuppressWarnings({
    
    "rawtypes","unchecked"})
    Node<K,V>[] newTab = (Node<K,V>[])new Node[newCap];
    table = newTab;
    if (oldTab != null) {
    
    
	 	//for循环把oldTab中的每个节点node,reHash操作并移动到新的数组newTab中
        for (int j = 0; j < oldCap; ++j) {
    
    
            Node<K,V> e;
            if ((e = oldTab[j]) != null) {
    
    
                oldTab[j] = null;
                // 若是单个节点,即没有后继next节点,则直接 newTab 在进行重定位
                if (e.next == null)
                    newTab[e.hash & (newCap - 1)] = e;
                //若节点为TreeNode,则需要进行红黑树的rehash操作
                else if (e instanceof TreeNode)
                    ((TreeNode<K,V>)e).split(this, newTab, j, oldCap);
                //else则节点为链表,需进行链表的rehash操作,链表重组并保持原有顺序
                else {
    
     // preserve order
                    Node<K,V> loHead = null, loTail = null;
                    Node<K,V> hiHead = null, hiTail = null;
                    Node<K,V> next;
                    do {
    
    
                        next = e.next;
                        //通过与位运算&,判断rehash后节点位置是否发生改变
                        if ((e.hash & oldCap) == 0) {
    
    
                            if (loTail == null)
                                //loHead 指向新的 hash 在原位置的头节点
                                loHead = e;
                            else
                                //loTail 指向新的 hash 在原位置的尾节点
                                loTail.next = e;
                            loTail = e;
                        }
                        //else则rehash后节点位置变为:原位置+oldCap位置
                        else {
    
    
                            if (hiTail == null)
                                hiHead = e;
                            else
                                hiTail.next = e;
                            hiTail = e;
                        }
                    } while ((e = next) != null);
                    if (loTail != null) {
    
    
                        loTail.next = null;
                        newTab[j] = loHead;
                    }
                    if (hiTail != null) {
    
    
                        hiTail.next = null;
                        newTab[j + oldCap] = hiHead;
                    }
                }
            }
        }
    }
    return newTab;
}

Guess you like

Origin blog.csdn.net/qq_37248504/article/details/113574720