作者丨HUC南枫 来源丨甲哇技术栈(jiawa1024)ArrayList 的底层是数组队列,相当于动态数组。与 Java 中的数组相比,它的容量能动态增长。在添加大量元素前,应用程序可以使用ensureCapacity操作来增加 ArrayList 实例的容量。这可以减少递增式再分配的数量。 它继承于 AbstractList,实现了 List, RandomAccess, Cloneable, java.io.Serializable 这些接口。在我们学数据结构的时候就知道了线性表的顺序存储,插入删除元素的时间复杂度为O(n),求表长以及增加元素,取第 i   元素的时间复杂度为O(1)ArrayList 继承了AbstractList,实现了List。它是一个数组队列,提供了相关的添加、删除、修改、遍历等功能。ArrayList 实现了RandomAccess 接口, RandomAccess 是一个标志接口,表明实现这个这个接口的 List 集合是支持快速随机访问的。在 ArrayList 中,我们即可以通过元素的序号快速获取元素对象,这就是快速随机访问。ArrayList 实现了Cloneable 接口,即覆盖了函数 clone(),能被克隆。ArrayList 实现java.io.Serializable 接口,这意味着ArrayList支持序列化,能通过序列化去传输。和 Vector 不同,ArrayList 中的操作不是线程安全的!所以,建议在单线程中才使用 ArrayList,而在多线程中可以选择 Vector 或者  CopyOnWriteArrayList。

ArrayList核心源码

package java.util;import java.util.function.Consumer;import java.util.function.Predicate;import java.util.function.UnaryOperator;public class ArrayList extends AbstractList        implements List, RandomAccess, Cloneable, java.io.Serializable{    private static final long serialVersionUID = 8683452581122892189L;    /**     * 默认初始容量大小     */    private static final int DEFAULT_CAPACITY = 10;    /**     * 空数组(用于空实例)。     */    private static final Object[] EMPTY_ELEMENTDATA = {};     //用于默认大小空实例的共享空数组实例。      //我们把它从EMPTY_ELEMENTDATA数组中区分出来,以知道在添加第一个元素时容量需要增加多少。    private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};    /**     * 保存ArrayList数据的数组     */    transient Object[] elementData; // non-private to simplify nested class access    /**     * ArrayList 所包含的元素个数     */    private int size;    /**     * 带初始容量参数的构造函数。(用户自己指定容量)     */    public ArrayList(int initialCapacity) {        if (initialCapacity > 0) {            //创建initialCapacity大小的数组            this.elementData = new Object[initialCapacity];        } else if (initialCapacity == 0) {            //创建空数组            this.elementData = EMPTY_ELEMENTDATA;        } else {            throw new IllegalArgumentException("Illegal Capacity: "+                                               initialCapacity);        }    }    /**     *默认构造函数,DEFAULTCAPACITY_EMPTY_ELEMENTDATA 为0.初始化为10,也就是说初始其实是空数组 当添加第一个元素的时候数组容量才变成10     */    public ArrayList() {        this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;    }    /**     * 构造一个包含指定集合的元素的列表,按照它们由集合的迭代器返回的顺序。     */    public ArrayList(Collection extends E> c) {        //        elementData = c.toArray();        //如果指定集合元素个数不为0        if ((size = elementData.length) != 0) {            // c.toArray 可能返回的不是Object类型的数组所以加上下面的语句用于判断,            //这里用到了反射里面的getClass()方法            if (elementData.getClass() != Object[].class)                elementData = Arrays.copyOf(elementData, size, Object[].class);        } else {            // 用空数组代替            this.elementData = EMPTY_ELEMENTDATA;        }    }    /**     * 修改这个ArrayList实例的容量是列表的当前大小。应用程序可以使用此操作来最小化ArrayList实例的存储。     */    public void trimToSize() {        modCount++;        if (size < elementData.length) {            elementData = (size == 0)              ? EMPTY_ELEMENTDATA              : Arrays.copyOf(elementData, size);        }    }//下面是ArrayList的扩容机制//ArrayList的扩容机制提高了性能,如果每次只扩充一个,//那么频繁的插入会导致频繁的拷贝,降低性能,而ArrayList的扩容机制避免了这种情况。    /**     * 如有必要,增加此ArrayList实例的容量,以确保它至少能容纳元素的数量     * @param   minCapacity   所需的最小容量     */    public void ensureCapacity(int minCapacity) {        int minExpand = (elementData != DEFAULTCAPACITY_EMPTY_ELEMENTDATA)            // any size if not default element table            ? 0            // larger than default for default empty table. It's already            // supposed to be at default size.            : DEFAULT_CAPACITY;        if (minCapacity > minExpand) {            ensureExplicitCapacity(minCapacity);        }    }   //得到最小扩容量    private void ensureCapacityInternal(int minCapacity) {        if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {              // 获取默认的容量和传入参数的较大值            minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);        }        ensureExplicitCapacity(minCapacity);    }  //判断是否需要扩容    private void ensureExplicitCapacity(int minCapacity) {        modCount++;        // overflow-conscious code        if (minCapacity - elementData.length > 0)            //调用grow方法进行扩容,调用此方法代表已经开始扩容了            grow(minCapacity);    }    /**     * 要分配的最大数组大小     */    private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;    /**     * ArrayList扩容的核心方法。     */    private void grow(int minCapacity) {        // oldCapacity为旧容量,newCapacity为新容量        int oldCapacity = elementData.length;        //将oldCapacity 右移一位,其效果相当于oldCapacity /2,        //我们知道位运算的速度远远快于整除运算,整句运算式的结果就是将新容量更新为旧容量的1.5倍,        int newCapacity = oldCapacity + (oldCapacity >> 1);        //然后检查新容量是否大于最小需要容量,若还是小于最小需要容量,那么就把最小需要容量当作数组的新容量,        if (newCapacity - minCapacity < 0)            newCapacity = minCapacity;        //再检查新容量是否超出了ArrayList所定义的最大容量,        //若超出了,则调用hugeCapacity()来比较minCapacity和 MAX_ARRAY_SIZE,        //如果minCapacity大于MAX_ARRAY_SIZE,则新容量则为Interger.MAX_VALUE,否则,新容量大小则为 MAX_ARRAY_SIZE。        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);    }    //比较minCapacity和 MAX_ARRAY_SIZE    private static int hugeCapacity(int minCapacity) {        if (minCapacity < 0) // overflow            throw new OutOfMemoryError();        return (minCapacity > MAX_ARRAY_SIZE) ?            Integer.MAX_VALUE :            MAX_ARRAY_SIZE;    }    /**     *返回此列表中的元素数。     */    public int size() {        return size;    }    /**     * 如果此列表不包含元素,则返回 true 。     */    public boolean isEmpty() {        //注意=和==的区别        return size == 0;    }    /**     * 如果此列表包含指定的元素,则返回true 。     */    public boolean contains(Object o) {        //indexOf()方法:返回此列表中指定元素的首次出现的索引,如果此列表不包含此元素,则为-1        return indexOf(o) >= 0;    }    /**     *返回此列表中指定元素的首次出现的索引,如果此列表不包含此元素,则为-1     */    public int indexOf(Object o) {        if (o == null) {            for (int i = 0; i < size; i++)                if (elementData[i]==null)                    return i;        } else {            for (int i = 0; i < size; i++)                //equals()方法比较                if (o.equals(elementData[i]))                    return i;        }        return -1;    }    /**     * 返回此列表中指定元素的最后一次出现的索引,如果此列表不包含元素,则返回-1。.     */    public int lastIndexOf(Object o) {        if (o == null) {            for (int i = size-1; i >= 0; i--)                if (elementData[i]==null)                    return i;        } else {            for (int i = size-1; i >= 0; i--)                if (o.equals(elementData[i]))                    return i;        }        return -1;    }    /**     * 返回此ArrayList实例的浅拷贝。(元素本身不被复制。)     */    public Object clone() {        try {            ArrayList> v = (ArrayList>) super.clone();            //Arrays.copyOf功能是实现数组的复制,返回复制后的数组。参数是被复制的数组和复制的长度            v.elementData = Arrays.copyOf(elementData, size);            v.modCount = 0;            return v;        } catch (CloneNotSupportedException e) {            // 这不应该发生,因为我们是可以克隆的            throw new InternalError(e);        }    }    /**     *以正确的顺序(从第一个到最后一个元素)返回一个包含此列表中所有元素的数组。     *返回的数组将是“安全的”,因为该列表不保留对它的引用。(换句话说,这个方法必须分配一个新的数组)。     *因此,调用者可以自由地修改返回的数组。此方法充当基于阵列和基于集合的API之间的桥梁。     */    public Object[] toArray() {        return Arrays.copyOf(elementData, size);    }    /**     * 以正确的顺序返回一个包含此列表中所有元素的数组(从第一个到最后一个元素);     *返回的数组的运行时类型是指定数组的运行时类型。如果列表适合指定的数组,则返回其中。     *否则,将为指定数组的运行时类型和此列表的大小分配一个新数组。     *如果列表适用于指定的数组,其余空间(即数组的列表数量多于此元素),则紧跟在集合结束后的数组中的元素设置为null 。     *(这仅在调用者知道列表不包含任何空元素的情况下才能确定列表的长度。)     */    @SuppressWarnings("unchecked")    public  T[] toArray(T[] a) {        if (a.length < size)            // 新建一个运行时类型的数组,但是ArrayList数组的内容            return (T[]) Arrays.copyOf(elementData, size, a.getClass());            //调用System提供的arraycopy()方法实现数组之间的复制        System.arraycopy(elementData, 0, a, 0, size);        if (a.length > size)            a[size] = null;        return a;    }    // Positional Access Operations    @SuppressWarnings("unchecked")    E elementData(int index) {        return (E) elementData[index];    }    /**     * 返回此列表中指定位置的元素。     */    public E get(int index) {        rangeCheck(index);        return elementData(index);    }    /**     * 用指定的元素替换此列表中指定位置的元素。     */    public E set(int index, E element) {        //对index进行界限检查        rangeCheck(index);        E oldValue = elementData(index);        elementData[index] = element;        //返回原来在这个位置的元素        return oldValue;    }    /**     * 将指定的元素追加到此列表的末尾。     */    public boolean add(E e) {        ensureCapacityInternal(size + 1);  // Increments modCount!!        //这里看到ArrayList添加元素的实质就相当于为数组赋值        elementData[size++] = e;        return true;    }    /**     * 在此列表中的指定位置插入指定的元素。     *先调用 rangeCheckForAdd 对index进行界限检查;然后调用 ensureCapacityInternal 方法保证capacity足够大;     *再将从index开始之后的所有成员后移一个位置;将element插入index位置;最后size加1。     */    public void add(int index, E element) {        rangeCheckForAdd(index);        ensureCapacityInternal(size + 1);  // Increments modCount!!        //arraycopy()这个实现数组之间复制的方法一定要看一下,下面就用到了arraycopy()方法实现数组自己复制自己        System.arraycopy(elementData, index, elementData, index + 1,                         size - index);        elementData[index] = element;        size++;    }    /**     * 删除该列表中指定位置的元素。将任何后续元素移动到左侧(从其索引中减去一个元素)。     */    public E remove(int index) {        rangeCheck(index);        modCount++;        E oldValue = elementData(index);        int numMoved = size - index - 1;        if (numMoved > 0)            System.arraycopy(elementData, index+1, elementData, index,                             numMoved);        elementData[--size] = null; // clear to let GC do its work      //从列表中删除的元素        return oldValue;    }    /**     * 从列表中删除指定元素的第一个出现(如果存在)。如果列表不包含该元素,则它不会更改。     *返回true,如果此列表包含指定的元素     */    public boolean remove(Object o) {        if (o == null) {            for (int index = 0; index < size; index++)                if (elementData[index] == null) {                    fastRemove(index);                    return true;                }        } else {            for (int index = 0; index < size; index++)                if (o.equals(elementData[index])) {                    fastRemove(index);                    return true;                }        }        return false;    }    /*     * Private remove method that skips bounds checking and does not     * return the value removed.     */    private void fastRemove(int index) {        modCount++;        int numMoved = size - index - 1;        if (numMoved > 0)            System.arraycopy(elementData, index+1, elementData, index,                             numMoved);        elementData[--size] = null; // clear to let GC do its work    }    /**     * 从列表中删除所有元素。     */    public void clear() {        modCount++;        // 把数组中所有的元素的值设为null        for (int i = 0; i < size; i++)            elementData[i] = null;        size = 0;    }    /**     * 按指定集合的Iterator返回的顺序将指定集合中的所有元素追加到此列表的末尾。     */    public boolean addAll(Collection extends E> c) {        Object[] a = c.toArray();        int numNew = a.length;        ensureCapacityInternal(size + numNew);  // Increments modCount        System.arraycopy(a, 0, elementData, size, numNew);        size += numNew;        return numNew != 0;    }    /**     * 将指定集合中的所有元素插入到此列表中,从指定的位置开始。     */    public boolean addAll(int index, Collection extends E> c) {        rangeCheckForAdd(index);        Object[] a = c.toArray();        int numNew = a.length;        ensureCapacityInternal(size + numNew);  // Increments modCount        int numMoved = size - index;        if (numMoved > 0)            System.arraycopy(elementData, index, elementData, index + numNew,                             numMoved);        System.arraycopy(a, 0, elementData, index, numNew);        size += numNew;        return numNew != 0;    }    /**     * 从此列表中删除所有索引为fromIndex (含)和toIndex之间的元素。     *将任何后续元素移动到左侧(减少其索引)。     */    protected void removeRange(int fromIndex, int toIndex) {        modCount++;        int numMoved = size - toIndex;        System.arraycopy(elementData, toIndex, elementData, fromIndex,                         numMoved);        // clear to let GC do its work        int newSize = size - (toIndex-fromIndex);        for (int i = newSize; i < size; i++) {            elementData[i] = null;        }        size = newSize;    }    /**     * 检查给定的索引是否在范围内。     */    private void rangeCheck(int index) {        if (index >= size)            throw new IndexOutOfBoundsException(outOfBoundsMsg(index));    }    /**     * add和addAll使用的rangeCheck的一个版本     */    private void rangeCheckForAdd(int index) {        if (index > size || index < 0)            throw new IndexOutOfBoundsException(outOfBoundsMsg(index));    }    /**     * 返回IndexOutOfBoundsException细节信息     */    private String outOfBoundsMsg(int index) {        return "Index: "+index+", Size: "+size;    }    /**     * 从此列表中删除指定集合中包含的所有元素。     */    public boolean removeAll(Collection> c) {        Objects.requireNonNull(c);        //如果此列表被修改则返回true        return batchRemove(c, false);    }    /**     * 仅保留此列表中包含在指定集合中的元素。     *换句话说,从此列表中删除其中不包含在指定集合中的所有元素。     */    public boolean retainAll(Collection> c) {        Objects.requireNonNull(c);        return batchRemove(c, true);    }    /**     * 从列表中的指定位置开始,返回列表中的元素(按正确顺序)的列表迭代器。     *指定的索引表示初始调用将返回的第一个元素为next 。初始调用previous将返回指定索引减1的元素。     *返回的列表迭代器是fail-fast 。     */    public ListIterator listIterator(int index) {        if (index < 0 || index > size)            throw new IndexOutOfBoundsException("Index: "+index);        return new ListItr(index);    }    /**     *返回列表中的列表迭代器(按适当的顺序)。     *返回的列表迭代器是fail-fast 。     */    public ListIterator listIterator() {        return new ListItr(0);    }    /**     *以正确的顺序返回该列表中的元素的迭代器。     *返回的迭代器是fail-fast 。     */    public Iterator iterator() {        return new Itr();    }  

ArrayList源码分析

System.arraycopy()和Arrays.copyOf()方法

通过上面源码我们发现这两个实现数组复制的方法被广泛使用而且很多地方都特别巧妙。比如下面add(int index, E element)方法就很巧妙的用到了arraycopy()方法让数组自己复制自己实现让index开始之后的所有成员后移一个位置:

    /**     * 在此列表中的指定位置插入指定的元素。     *先调用 rangeCheckForAdd 对index进行界限检查;然后调用 ensureCapacityInternal 方法保证capacity足够大;     *再将从index开始之后的所有成员后移一个位置;将element插入index位置;最后size加1。     */    public void add(int index, E element) {        rangeCheckForAdd(index);        ensureCapacityInternal(size + 1);  // Increments modCount!!        //arraycopy()方法实现数组自己复制自己        //elementData:源数组;index:源数组中的起始位置;elementData:目标数组;index + 1:目标数组中的起始位置;size - index:要复制的数组元素的数量;        System.arraycopy(elementData, index, elementData, index + 1, size - index);        elementData[index] = element;        size++;    }

又如toArray()方法中用到了copyOf()方法

    /**     *以正确的顺序(从第一个到最后一个元素)返回一个包含此列表中所有元素的数组。     *返回的数组将是“安全的”,因为该列表不保留对它的引用。(换句话说,这个方法必须分配一个新的数组)。     *因此,调用者可以自由地修改返回的数组。此方法充当基于阵列和基于集合的API之间的桥梁。     */    public Object[] toArray() {    //elementData:要复制的数组;size:要复制的长度        return Arrays.copyOf(elementData, size);    }
两者联系与区别

解析:看两者源代码可以发现copyOf()内部调用了System.arraycopy()方法区别:

  1. arraycopy()需要目标数组,将原数组拷贝到你自己定义的数组里,而且可以选择拷贝的起点和长度以及放入新数组中的位置
  2. copyOf()是系统自动在内部新建一个数组,并返回该数组。

ArrayList 核心扩容技术

//下面是ArrayList的扩容机制//ArrayList的扩容机制提高了性能,如果每次只扩充一个,//那么频繁的插入会导致频繁的拷贝,降低性能,而ArrayList的扩容机制避免了这种情况。    /**     * 如有必要,增加此ArrayList实例的容量,以确保它至少能容纳元素的数量     * @param   minCapacity   所需的最小容量     */    public void ensureCapacity(int minCapacity) {        int minExpand = (elementData != DEFAULTCAPACITY_EMPTY_ELEMENTDATA)            // any size if not default element table            ? 0            // larger than default for default empty table. It's already            // supposed to be at default size.            : DEFAULT_CAPACITY;        if (minCapacity > minExpand) {            ensureExplicitCapacity(minCapacity);        }    }   //得到最小扩容量    private void ensureCapacityInternal(int minCapacity) {        if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {              // 获取默认的容量和传入参数的较大值            minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);        }        ensureExplicitCapacity(minCapacity);    }  //判断是否需要扩容,上面两个方法都要调用    private void ensureExplicitCapacity(int minCapacity) {        modCount++;        // 如果说minCapacity也就是所需的最小容量大于保存ArrayList数据的数组的长度的话,就需要调用grow(minCapacity)方法扩容。        //这个minCapacity到底为多少呢?举个例子在添加元素(add)方法中这个minCapacity的大小就为现在数组的长度加1        if (minCapacity - elementData.length > 0)            //调用grow方法进行扩容,调用此方法代表已经开始扩容了            grow(minCapacity);    }
    /**     * ArrayList扩容的核心方法。     */    private void grow(int minCapacity) {       //elementData为保存ArrayList数据的数组       ///elementData.length求数组长度elementData.size是求数组中的元素个数        // oldCapacity为旧容量,newCapacity为新容量        int oldCapacity = elementData.length;        //将oldCapacity 右移一位,其效果相当于oldCapacity /2,        //我们知道位运算的速度远远快于整除运算,整句运算式的结果就是将新容量更新为旧容量的1.5倍,        int newCapacity = oldCapacity + (oldCapacity >> 1);        //然后检查新容量是否大于最小需要容量,若还是小于最小需要容量,那么就把最小需要容量当作数组的新容量,        if (newCapacity - minCapacity < 0)            newCapacity = minCapacity;        //再检查新容量是否超出了ArrayList所定义的最大容量,        //若超出了,则调用hugeCapacity()来比较minCapacity和 MAX_ARRAY_SIZE,        //如果minCapacity大于MAX_ARRAY_SIZE,则新容量则为Interger.MAX_VALUE,否则,新容量大小则为 MAX_ARRAY_SIZE。        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);    }    

扩容机制代码已经做了详细的解释。另外值得注意的是大家很容易忽略的一个运算符:移位运算符简介:移位运算符就是在二进制的基础上对数字进行平移。按照平移的方向和填充数字的规则分为三种:<>(带符号右移)和>>>(无符号右移)。作用:对于大数据的2进制运算,位移运算符比那些普通运算符的运算要快很多,因为程序仅仅移动一下而已,不去计算,这样提高了效率,节省了资源  比如这里:int newCapacity = oldCapacity + (oldCapacity >> 1);右移一位相当于除2,右移n位相当于除以 2 的 n 次方。这里 oldCapacity 明显右移了1位所以相当于oldCapacity /2。另外需要注意的是:

  1. java 中的length 属性是针对数组说的,比如说你声明了一个数组,想知道这个数组的长度则用到了 length 这个属性.
  2. java 中的length()方法是针对字  符串String说的,如果想看这个字符串的长度则用到 length()这个方法.
  3. .java 中的size()方法是针对泛型集合说的,如果想看这个泛型有多少个元素,就调用此方法来查看!

内部类

    (1)private class Itr implements Iterator      (2)private class ListItr extends Itr implements ListIterator      (3)private class SubList extends AbstractList implements RandomAccess      (4)static final class ArrayListSpliterator implements Spliterator  

ArrayList有四个内部类,其中的Itr是实现了Iterator接口,同时重写了里面的hasNext(),next(),remove()等方法;其中的ListItr继承Itr,实现了ListIterator接口,同时重写了hasPrevious(),nextIndex(),previousIndex(),previous(),set(E e),add(E e)等方法,所以这也可以看出了 Iterator和ListIterator的区别:ListIterator在Iterator的基础上增加了添加对象,修改对象,逆向遍历等方法,这些是Iterator不能实现的。

package list;import java.util.ArrayList;import java.util.Iterator;public class ArrayListDemo {    public static void main(String[] srgs){         ArrayList<Integer> arrayList = new ArrayList<Integer>();         System.out.printf("Before add:arrayList.size() = %d\n",arrayList.size());         arrayList.add(1);         arrayList.add(3);         arrayList.add(5);         arrayList.add(7);         arrayList.add(9);         System.out.printf("After add:arrayList.size() = %d\n",arrayList.size());         System.out.println("Printing elements of arrayList");         // 三种遍历方式打印元素         // 第一种:通过迭代器遍历         System.out.print("通过迭代器遍历:");         Iterator<Integer> it = arrayList.iterator();         while(it.hasNext()){             System.out.print(it.next() + " ");         }         System.out.println();         // 第二种:通过索引值遍历         System.out.print("通过索引值遍历:");         for(int i = 0; i < arrayList.size(); i++){             System.out.print(arrayList.get(i) + " ");         }         System.out.println();         // 第三种:for循环遍历         System.out.print("for循环遍历:");         for(Integer number : arrayList){             System.out.print(number + " ");         }         // toArray用法         // 第一种方式(最常用)         Integer[] integer = arrayList.toArray(new Integer[0]);         // 第二种方式(容易理解)         Integer[] integer1 = new Integer[arrayList.size()];         arrayList.toArray(integer1);         // 抛出异常,java不支持向下转型         //Integer[] integer2 = new Integer[arrayList.size()];         //integer2 = arrayList.toArray();         System.out.println();         // 在指定位置添加元素         arrayList.add(2,2);         // 删除指定位置上的元素         arrayList.remove(2);             // 删除指定元素         arrayList.remove((Object)3);         // 判断arrayList是否包含5         System.out.println("ArrayList contains 5 is: " + arrayList.contains(5));         // 清空ArrayList         arrayList.clear();         // 判断ArrayList是否为空         System.out.println("ArrayList is empty: " + arrayList.isEmpty());    }}

近期精彩内容推荐:  

 妹子 rm -rf 把公司整个数据库删没了...

 当互联网码农遇见国企老同学

 推荐33个IDEA最牛配置,写代码太爽了

 Python中zip()函数的解释和可视化

在看点这里好文分享给更多人↓↓

arraylist 的扩容机制_ArrayList详解相关推荐

  1. arraylist扩容是创建新数组吗 java_Java ArrayList扩容问题实例详解

    本文研究的主要是Java ArrayList扩容问题实例详解的相关内容,具体介绍如下. 首先我们需要知道ArrayList里面的实质的其实是一个Object类型的数组,ArrayList的扩容问题其实 ...

  2. mysql select 缓存_mysql select缓存机制使用详解

    mysql Query Cache 默认为打开.从某种程度可以提高查询的效果,但是未必是最优的解决方案,如果有的大量的修改和查询时,由于修改造成的cache失效,会给服务器造成很大的开销,可以通过qu ...

  3. java 委托机制_通过反射实现Java下的委托机制代码详解

    简述 一直对Java没有现成的委托机制耿耿于怀,所幸最近有点时间,用反射写了一个简单的委托模块,以供参考. 模块API public Class Delegater()//空参构造,该类管理委托实例并 ...

  4. java委托机制教程_通过反射实现Java下的委托机制代码详解

    简述 一直对java没有现成的委托机制耿耿于怀,所幸最近有点时间,用反射写了一个简单的委托模块,以供参考. 模块api public class delegater()//空参构造,该类管理委托实例并 ...

  5. python做插件应用_Python插件机制实现详解

    插件机制是代码/功能反向依赖注入到主体程序的一种方法,编译型语言通过动态加载动态库实现插件.对于Python这样的脚本语言,实现插件机制更简单. 机制 Python的__import__方法可以动态地 ...

  6. python插件使用教程_Python插件机制实现详解

    插件机制是代码/功能反向依赖注入到主体程序的一种方法,编译型语言通过动态加载动态库实现插件.对于Python这样的脚本语言,实现插件机制更简单. 机制 Python的__import__方法可以动态地 ...

  7. java反射机制深入详解_Java反射机制深入详解

    原标题:Java反射机制深入详解 一.概念 反射就是把Java的各种成分映射成相应的Java类. Class类的构造方法是private,由JVM创建. 反射是java语言的一个特性,它允程序在运行时 ...

  8. python加载机制_Python插件机制实现详解

    插件机制是代码/功能反向依赖注入到主体程序的一种方法,编译型语言通过动态加载动态库实现插件.对于Python这样的脚本语言,实现插件机制更简单. 机制 Python的__import__方法可以动态地 ...

  9. Linux per_cpu机制的详解

    Linux per_cpu机制的详解 针对IA64体系结构 在Linux操作系统中,特别是针对SMP或者NUMA架构的多CPU系统的时候,描述每个CPU的私有数据的时候,Linux操作系统提供了per ...

最新文章

  1. train_test_split()
  2. sgd 参数 详解_代码笔记--PC-DARTS代码详解
  3. Android ViewStub
  4. STM32F0xx_ADC采集电压配置详细过程
  5. 使用SQL Storage Compress压缩SQL Server 数据库文件
  6. JavaScript学习(三十一)—在输入框中如何判断输入的是一个正确的网址
  7. QT开发_弹出窗口禁用父窗口并移动到父窗口中心位置
  8. 小白能读懂的 《手把手教你学DSP(TMS320X281X)》第六章 时钟和系统控制
  9. 推荐 7 个神级 Java 开源项目
  10. 论文公式自动编号及引用(自动更新)
  11. 词法分析之LED文件生成程序【调试中......】
  12. RAID 磁盘阵列详解,RAID分类及优缺点
  13. #1005. 三个小朋友分糖果
  14. 大型软件工作站计算机性能配置要求,推荐配置7.3万元的高性能服务器计算机工作站(全文)...
  15. 腾讯「文涌 (Effidit)」2.0版发布,打造更懂写作的智能助手
  16. 根据出生日期判断星座
  17. 人机对话是怎么产生的?
  18. 如何完美快速地卸载office2007,2010,2013,2016
  19. Unix平台下iostat与vmstst说明
  20. 神码ai人工智能写作机器人_神经符号AI为我们提供具有真正常识的机器

热门文章

  1. oracle从光盘启动不了,oracle install
  2. Python使用装饰器捕获异常
  3. Java后台POST请求以application/x-www-form-urlencoded;charset=utf-8格式
  4. 1.详细说明微型计算机的组成,第1章微型计算机系统导论.ppt
  5. html获取文件路径_HTML 文件路径
  6. 在windows 服务中 调打印_Windows打印后台处理程序漏洞(CVE20201048)
  7. 新员工入职表_入职培训流程,五大步骤让员工顺利上岗,来之能战战之能胜
  8. 优雅的使用springboot集成任务调度
  9. 向Redis中存入JSON格式数据
  10. 各个系统下关闭占用端口号的进程