Java容器

108 阅读3分钟

ArrayList源码分析

image.png

add()过程源码如下

// eg1:第一次新增元素e="a1",
    public boolean add(E e) {
        /** 确定是否需要扩容,如果需要,则进行扩容操作*/
        ensureCapacityInternal(size + 1);  // Increments modCount!!
        // eg1:size=0,elementData[0]="a1",然后a自增为1
        elementData[size++] = e;
        return true;
    }

// eg1:第一次新增元素,elementData={} minCapacity=1
    private static int calculateCapacity(Object[] elementData, int minCapacity) {
        if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
            //检查elementData是否为空数组
            // eg1:满足if判断,DEFAULT_CAPACITY=10
            return Math.max(DEFAULT_CAPACITY, minCapacity);
        }
        return minCapacity;
    }



// eg1:第一次新增元素,minCapacity=10
    private void ensureExplicitCapacity(int minCapacity) {
        // eg1: modCount++后,modCount=1
        modCount++;


        /** 如果所需的最小容量大于elementData数组的容量,则进行扩容操作 */
        if (minCapacity - elementData.length > 0) { // eg1:10-0=10,满足扩容需求
            // eg1:minCapacity=10
            grow(minCapacity);
        }
    }



// eg1:第一次新增元素,minCapacity=10,即:需要将elementData的0长度扩容为10长度。
    private void grow(int minCapacity) {

        /** 原有数组elementData的长度*/
        int oldCapacity = elementData.length; // eg1:oldCapacity=0

        /**
         * A >> 1 等于 A/2
         * eg: 3 >> 1 = 3/2 = 1
         *     4 >> 1 = 4/2 = 2
         * ------------------------
         * A << 1 等于 A*2
         * eg: 3 << 1 = 3*2 = 6
         *     4 << 1 = 4*2 = 8
         *
         * 000100 >> 1 = 000010
         * 000100 << 1 = 001000
         */
        /** 新增oldCapacity的一半整数长度作为newCapacity的额外增长长度 */
        int newCapacity = oldCapacity + (oldCapacity >> 1); // eg1:newCapacity=0+(0>>1)=0

        /** 新的长度newCapacity依然无法满足需要的最小扩容量minCapacity,
            则新的扩容长度为minCapacity */
        if (newCapacity - minCapacity < 0) {
            // eg1:newCapacity=10
            newCapacity = minCapacity;
        }

        /** 新的扩容长度newCapacity超出了最大的数组长度MAX_ARRAY_SIZE */
        if (newCapacity - MAX_ARRAY_SIZE > 0) {
            newCapacity = hugeCapacity(minCapacity);
        }

        /** 扩展数组长度为newCapacity,并且将旧数组中的元素赋值到新的数组中 */
        // eg1:newCapacity=10, 扩容elementData的length=10
        elementData = Arrays.copyOf(elementData, newCapacity);
    }

get()过程源码如下

public E get(int index) {
        rangeCheck(index);

        return elementData(index);
    }

private void rangeCheck(int index) {
        if (index >= size) {
            throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
        }
    }

    @SuppressWarnings("unchecked")
    E elementData(int index) {
        return (E) elementData[index];
    }

set()过程源码如下

public E set(int index, E element) {
        //判断是否越界
        rangeCheck(index);

        E oldValue = elementData(index);
        elementData[index] = element;
        return oldValue;
    }

remove()过程源码如下:

public E remove(int index) {
        /** 校验传入的参数index是否超出了数组的最大下标,
            如果超出,则抛出:IndexOutOfBoundsException异常*/
        rangeCheck(index);

        modCount++;

        // eg1:String oldValue="a1"
        E oldValue = elementData(index);

        // eg1:numMoved=4-0-1=3
        int numMoved = size - index - 1;
        if (numMoved > 0) {
            /** 从需要删除的index后一位开始到末尾的这部分数据,整体都向前移动一个元素。*/
            System.arraycopy(elementData, index + 1, elementData, index,
                    numMoved);
        }
        // 通知jvm将之前的最后一位元素进行垃圾回收
        elementData[--size] = null; // clear to let GC do its work

        return oldValue; // 返回已被删除的元素
    }

LinkedList源码分析

image.png

add() 过程源码

public boolean add(E e) {
        linkLast(e);
        return true;
    }


void linkLast(E e) {
        final Node<E> l = last;
        // eg1: newNode    null<--"a1"-->null
        final Node<E> newNode = new Node<>(l, e, null);
        last = newNode;
        // eg1: l=null
        if (l == null) {
            /** 如果是第一个添加的元素,则first指针指向该结点*/
            first = newNode; // eg1: first指向newNode
        } else {
            /** 如果不是第一个添加进来的元素,则更新l的后置结点指向新添加的元素结点*/
            l.next = newNode;
        }
        size++;
        modCount++;
    }

HashMap源码分析

image.png

final Node<K, V>[] resize() {
 
        Node<K, V>[] oldTab = table;
        int oldCap = (oldTab == null) ? 0 : oldTab.length;
        int oldThr = threshold;
        int newCap = 0;
        int newThr = 0;
        /** 第一步:根据情况,调整新表的容量newCap和阈值newThr*/
        if (oldCap > 0) {
            /** 如果老table的长度大于等于2^30(1 << 30)        1后面有30个0*/
            if (oldCap >= MAXIMUM_CAPACITY) {
                threshold = Integer.MAX_VALUE; /** 2^31-1  1后面有30个1 */
                return oldTab;
            }
            /** 如果将老Table的长度增长2倍作为新的容量长度(newCap),是否小于2^30(1 << 30) 并且 老Table长度是否大于等于16(1 << 4)*/
            else if ((newCap = oldCap << 1) < MAXIMUM_CAPACITY && oldCap >= DEFAULT_INITIAL_CAPACITY) {
                // eg6: newCap=32, newThr=24
                newThr = oldThr << 1;
            }
        } else if (oldThr > 0) {
            newCap = oldThr;
        } else {
            // eg1: oldCap=0 newCap=16 newThr=0.75f*16=12
            newCap = DEFAULT_INITIAL_CAPACITY; /** 默认【表容量】为16(1 << 4) */
            newThr = (int) (DEFAULT_LOAD_FACTOR * DEFAULT_INITIAL_CAPACITY); /** 默认【阈值因子】为0.75f */
        }

        if (newThr == 0) {
            float ft = (float) newCap * loadFactor;
            newThr = (newCap < MAXIMUM_CAPACITY && ft < (float) MAXIMUM_CAPACITY ? (int) ft : Integer.MAX_VALUE);
        }
       
        threshold = newThr;

        /** 第二步:根据newCap和newThr,构建新数组 */
        /** 初始化新表*/
        @SuppressWarnings({"rawtypes", "unchecked"})
        Node<K, V>[] newTab = (Node<K, V>[]) new Node[newCap];
        
        table = newTab;
        
        if (oldTab != null) { /** 如果老的table里有数据,则进行数据迁移*/
            for (int j = 0; j < oldCap; ++j) {
                Node<K, V> e;
               
                if ((e = oldTab[j]) != null) {
                    oldTab[j] = null;
                    if (e.next == null) { /** 没有后置节点,说明e是最后一个节点*/
                       
                        newTab[e.hash & (newCap - 1)] = e;
                    } else if (e instanceof TreeNode) { /** e是树节点*/
                        ((TreeNode<K, V>) e).split(this, newTab, j, oldCap);
                    } else {
                        Node<K, V> loHead = null;
                        Node<K, V> loTail = null;
                        Node<K, V> hiHead = null;
                        Node<K, V> hiTail = null;
                        Node<K, V> next;
                        do {
                            next = e.next; /** 获得oldTab数组下标的Node列表的下一个节点*/
                           
                            if ((e.hash & oldCap) == 0) { 
                          /** 计算e在老表oldTab的下标,如果是第一个Node,即:下标index==0*/
                                if (loTail == null) {
          
                              /** 将loHead指向oldTab数组第一个下标的第一个元素e*/
                                    loHead = e; 
                                } else {
                                   
                                    loTail.next = e;
                                }
                             
                            /** 将loTail指向oldTab数组第一个下标的最后一个元素e*/
                                loTail = e; 
                            }
                            else { /** 如果不是oldTab中的第一个下标Node*/
                                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;
    }