• java集合类之ArrayList详解


    一、ArrayList源码分析

    1、全局变量

    (1)默认容量(主要是通过无参构造函数创建ArrayList时第一次add执行扩容操作时指定的elementData的数组容量为10)

     private static final int DEFAULT_CAPACITY = 10;
    

    (2)空的对象数组(当通过指定容量的构造方法创建ArrayList时指定给elementData,用于区分DEFAULTCAPACITY_EMPTY_ELEMENTDATA,比如说在得到最小扩容容量时判断elementData是通过哪个构造函数指定的哪个数组)

     private static final Object[] EMPTY_ELEMENTDATA = {};
    

    (3)默认的空数组(用于区分EMPTY_ELEMENTDATA,主要针对构造函数)

     private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
    

    (4)存放数据的数组的缓存变量,不可序列化

     transient Object[] elementData;
    

    (5)元素数量(注意区分length,length是数组elementData的容量,而size是元素数量)

     private int size;
    

    2、构造函数

    (1)带有容量initialCapacity的构造方法

     public ArrayList(int initialCapacity) {
        if (initialCapacity > 0) {
            this.elementData = new Object[initialCapacity];
        } else if (initialCapacity == 0) {
            this.elementData = EMPTY_ELEMENTDATA;
        } else {
            throw new IllegalArgumentException("Illegal Capacity: "+
                                               initialCapacity);
        }
    }
    

    (2)不带参数的构造方法

     public ArrayList() {
        this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
    }
    

    (3)带参数Collection的构造方法

     public ArrayList(Collection<? extends E> c) {
        elementData = c.toArray();
        if ((size = elementData.length) != 0) {
            // c.toArray might (incorrectly) not return Object[] (see 6260652)
            if (elementData.getClass() != Object[].class)
                elementData = Arrays.copyOf(elementData, size, Object[].class);
        } else {
            // replace with empty array.
            this.elementData = EMPTY_ELEMENTDATA;
        }
    }
    

    参数c为一个Collection,Collection的实现类大概有以下几种常用类型:

    • List:元素可以重复的容器
    • Set: 元素不可重复的容器
    • Queue:结构是一个队列,先进先出
      这个构造方法的意思是,将一个Collection实现类的对象转换为一个ArrayList,但是c容器装的内容必须为ArrayList装的内容的子类。例如,将一个装了String内容的HashSet转换为装了String内容的ArrayList,使得ArrayList的大小和值数组都是HashSet的大小和值数组。具体实现如下代码,首先调用c(Collection的具体实现类)的toArray方法,具体大家可以看各个实现类的toArray方法,但是大概意思都是将c容器转换为object类型的数组,因为它们的返回值都是object[]。之于下面的两个判断是当得到的elementData的类名不是Object类名的时候或者是长度为0的时候才会执行。

    3、方法

    (1)trimToSize()

     public void trimToSize() {
        modCount++;
        if (size < elementData.length) {
            elementData = (size == 0)
              ? EMPTY_ELEMENTDATA
              : Arrays.copyOf(elementData, size);
        }
    }
    

    说明

    将ArrayList的容量设置为当前size的大小。首先需要明确一个概念,ArrayList的size就是ArrayList的元素个数,length是ArrayList申请的内容空间长度。ArrayList每次都会预申请多一点空间,以便添加元素的时候不需要每次都进行扩容操作,例如我们的元素个数是10个,它申请的内存空间必定会大于10,即length>size,而这个方法就是把ArrayList的内存空间设置为size,去除没有用到的null值空间。这也就是我们为什么每次在获取数据长度是都是调用list.size()而不是list.length()。(list不可调用length,因为不存在变量length)

    源码详解

    首先modCount是从类 java.util.AbstractList 继承的字段,这个字段主要是为了防止在多线程操作的情况下,List发生结构性的变化,什么意思呢?就是防止一个线程正在迭代,另外一个线程进行对List进行remove操作,这样当我们迭代到最后一个元素时,很明显此时List的最后一个元素为空,那么这时modCount就会告诉迭代器,让其抛出异常 ConcurrentModificationException。
    如果没有这一个变量,那么系统肯定会报异常ArrayIndexOutOfBoundsException,这样的异常显然不是应该出现的(这些运行时错误都是使用者的逻辑错误导致的,我们的JDK那么高端,不会出现使用错误,我们只抛出使用者造成的错误,而这个错误是设计者应该考虑的),为了避免出现这样的异常,定义了检查。

    (2)size()

     public int size() {
        return size;
    }
    

    说明:返回ArrayList的大小
    源码解释:直接返回size

    (3)isEmpty()

     public boolean isEmpty() {
        return size == 0;
    }
    

    说明:返回ArrayList是否为空
    解释说明:直接返回判断size==0

    (4)indexOf(Object o)

     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++)
                if (o.equals(elementData[i]))
                    return i;
        }
        return -1;
    }
    

    说明

    对象o在ArrayList中的下标位置,如果存在返回位置i,不存在返回-1
    源码解释

    遍历ArrayList的大小,比较o和容器内的元素,若相等,则返回位置i,若遍历完都不相等,返回-1

    (5)contails(Object o)

     public boolean contains(Object o) {
        return indexOf(o) >= 0;
    }
    

    说明

    是否包含对象o

    源码解释

    调用indexOf()方法得到下标,存在则下标>=0,不存在为-1,即只要比较下标和0的大小即可

    (6)lastIndexOf(Object o)

     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;
    }
    

    说明

    返回容器内出现o的最后一个位置

    源码解释

    从后向前遍历,得到第一个出现对象o的位置,不存在则返回-1

    (7)clone()

     public Object clone() {
        try {
            ArrayList<?> v = (ArrayList<?>) super.clone();
            v.elementData = Arrays.copyOf(elementData, size);
            v.modCount = 0;
            return v;
        } catch (CloneNotSupportedException e) {
            // this shouldn't happen, since we are Cloneable
            throw new InternalError(e);
        }
    }
    

    说明:返回此ArrayList实例的浅表副本

    (8)toArray()

     public Object[] toArray() {
        return Arrays.copyOf(elementData, size);
    }
    

    说明

    ArrayList实例转换为Array数组

    源码解释

    直接调用Arrays类的copyOf

    (9)toArray(T[] a)

     public <T> T[] toArray(T[] a) {
        if (a.length < size)
            // Make a new array of a's runtime type, but my contents:
            return (T[]) Arrays.copyOf(elementData, size, a.getClass());
        System.arraycopy(elementData, 0, a, 0, size);
        if (a.length > size)
            a[size] = null;
        return a;
    }
    

    说明

    将ArrayList里面的元素赋值到一个数组中去

    源码解释

    如果a的长度小于ArrayList的长度,直接调用Arrays类的copyOf,返回一个比a数组长度要大的新数组,里面元素就是ArrayList里面的元素;如果a的长度比ArrayList的长度大,那么就调用System.arraycopy,将ArrayList的elementData数组赋值到a数组,然后把a数组的size位置赋值为空

    (10)rangeCheck(int index)

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

    说明

    测试index是否越界

    源码解释

    如果index超出ArrayList的数组长度,就会抛出IndexOutOfBoundsException异常,注意 访问控制修饰符Private只能在同一类中使用

    (11)rangeCheckForAdd(int index)

     private void rangeCheckForAdd(int index) {
        if (index > size || index < 0)
            throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
    }
    

    说明:测试index是否越界(add、addall操作时)

    (12)get(int index)

     public E get(int index) {
        rangeCheck(index);
        return elementData(index);
    }
    

    说明:获取index位置的元素

    源码解释

    先检查是否越界,然后返回ArrayList的elementData数组index位置的元素

    (13)set(int index,E element)

     public E set(int index, E element) {
        rangeCheck(index);
        E oldValue = elementData(index);
        elementData[index] = element;
        return oldValue;
    }
    

    说明:设置index位置的元素值为element,返回该位置之前的值

    (14)ensureCapacityInternal(int minCapacity)

         private void ensureCapacityInternal(int minCapacity) {
        if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
        //获取默认的容量和传入参数的较大值
            minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
        }
        ensureExplicitCapacity(minCapacity);
    }
    

    说明:得到最小扩容量

    (15)ensureExplicitCapacity(int minCapacity)

     private void ensureExplicitCapacity(int minCapacity) {
        modCount++;
        //如果最小需要空间比ElementData的内存空间要大,则需要扩容
        // overflow-conscious code
        if (minCapacity - elementData.length > 0)
            grow(minCapacity);
    }
    

    说明:判断是否需要扩容

    (16)grow(int minCapacity)

     // MAX_VALUE为231-1,MAX_ARRAY_SIZE 就是获取Java中int的最大限制,以防止越界    
    private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;  
    private void grow(int minCapacity) {  
    // 获取到ArrayList中elementData数组的内存空间长度  
    int oldCapacity = elementData.length;  
    // 扩容至原来的1.5倍  
    int newCapacity = oldCapacity + (oldCapacity >> 1);  
    // 再判断一下新数组的容量够不够,够了就直接使用这个长度创建新数组,   
    // 不够就将数组长度设置为需要的长度  
    if (newCapacity - minCapacity < 0)  
        newCapacity = minCapacity;  
    // 判断有没超过最大限制  
    if (newCapacity - MAX_ARRAY_SIZE > 0)  
        newCapacity = hugeCapacity(minCapacity);  
    // 调用Arrays.copyOf方法将elementData数组指向新的内存空间时newCapacity的连续空间  
    // 并将elementData的数据复制到新的内存空间  
    elementData = Arrays.copyOf(elementData, newCapacity);  
    

    }

    说明:帮助ArrayList动态扩容的核心方法

    (17)hugeCapacity(int minCapacity)

     private static int hugeCapacity(int minCapacity) {
        if (minCapacity < 0) // overflow
            throw new OutOfMemoryError();
        return (minCapacity > MAX_ARRAY_SIZE) ?
            Integer.MAX_VALUE :
            MAX_ARRAY_SIZE;
    }
    

    说明:由grow(int minCapacity)调用

    (18)add(E e)

     public boolean add(E e) {  
     // 扩容  
        ensureCapacityInternal(size + 1);    
    // 将e赋值给elementData的size+1的位置。  
        elementData[size++] = e;  
        return true;  
    }  
    

    说明:添加元素e

    (19)add(int index,E element)

     public void add(int index, E element) {  
    // 判断index是否越界    
        rangeCheckForAdd(index);  
     // 扩容  
        ensureCapacityInternal(size + 1);    
     // 将elementData从index位置开始,复制到elementData的index+1开始的连续空间  
        System.arraycopy(elementData, index, elementData, index + 1,  
                     size - index);  
     // 在elementData的index位置赋值element  
        elementData[index] = element;  
     // ArrayList的大小加一    
        size++;  
    

    }

    说明:在ArrayList的index位置,添加元素element

    (20)remove(int index)

     public E remove(int index) {  
     // 判断是否越界    
        rangeCheck(index);  
        modCount++;  
     // 读取旧值    
        E oldValue = elementData(index);  
     // 获取index位置开始到最后一个位置的个数  
        int numMoved = size - index - 1;  
        if (numMoved > 0)  
         // 将elementData数组index+1位置开始拷贝到elementData从index开始的空间  
        System.arraycopy(elementData, index+1, elementData, index,  
                         numMoved);  
     // 使size-1 ,设置elementData的size位置为空,让GC来清理内存空间  
        elementData[--size] = null; // clear to let GC do its work  
        return oldValue;  
    }  
    

    说明:在ArrayList移除index位置的元素

    (21)remove(Object o)

     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;
    }
    

    说明:在ArrayList中移除对象为o的元素,跟indexOf方法的思想基本一致

    (22)fastRemove(int index)

     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
    }
    

    说明:被remove(Object o)调用

    (23)clear()

     public void clear() {
        modCount++;
        // clear to let GC do its work
        for (int i = 0; i < size; i++)
            elementData[i] = null;
        size = 0;
    }
    

    说明

    设置全部元素为null值,并设置size为0

    源码解释

    可见clear操作并不是从空间内删除,只是设置为null值,等待垃圾回收机制来回收而已,把size设置为0,以便我们不会浏览到null值的内存空间

    (24)addAll(Collection<? extend E> c)

     public boolean addAll(Collection<? extends E> c) {
     // 将c转换为数组a  
        Object[] a = c.toArray();  
     // 获取a占的内存空间长度赋值给numNew  
        int numNew = a.length;  
     // 扩容至size + numNew  
        ensureCapacityInternal(size + numNew);  // Increments modCount  
     // 将a的第0位开始拷贝至elementData的size位开始,拷贝长度为numNew  
        System.arraycopy(a, 0, elementData, size, numNew);  
     // 将size增加numNew    
        size += numNew;  
     // 如果c为空,返回false,c不为空,返回true  
        return numNew != 0;  
    

    }

    说明:将Collection c的全部元素添加到ArrayList中

    (25)addAll(int index,Collection<? extend E> c)

     public boolean addAll(int index, Collection<? extends E> c) {  
     // 判断index大于size或者是小于0,如果是,则抛出IndexOutOfBoundsException异常  
        rangeCheckForAdd(index);  
     // 将c转换为数组a  
        Object[] a = c.toArray();  
        int numNew = a.length;  
     // 扩容至size + numNew  
        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;  
    

    }

    说明:从第index位开始,将c全部拷贝到ArrayList

    (26)removeRange(int fromIndex,int 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;
    }
    

    说明:Removes from this list all of the elements whose index is between
    {@code fromIndex}, inclusive, and {@code toIndex}, exclusive.
    可以选择继承ArrayList编写自己的List类来调用这个方法
    (Protected访问控制修饰符)

    (27)batchRemove(Collection<?> c, boolean complement)

     private boolean batchRemove(Collection<?> c, boolean complement) {  
        final Object[] elementData = this.elementData;  
     // 定义一个w,一个r,两个同时右移     
        int r = 0, w = 0;  
        boolean modified = false;  
        try {  
         // r先右移  
            for (; r < size; r++)  
              // 如果c中不包含elementData[r]这个元素  
                if (c.contains(elementData[r]) == complement)  
                  // 则直接将r位置的元素赋值给w位置的元素,w自增  
                elementData[w++] = elementData[r];  
            } finally {  
        // 防止抛出异常导致上面r的右移过程没完成  
            if (r != size) {  
              // 将r未右移完成的位置的元素赋值给w右边位置的元素  
                System.arraycopy(elementData, r,  
                             elementData, w,  
                             size - r);  
              // 修改w值增加size-r  
                w += size - r;  
            }  
            if (w != size) {  
            // 如果有被覆盖掉的元素,则将w后面的元素都赋值为null  
                for (int i = w; i < size; i++)  
                    elementData[i] = null;  
                modCount += size - w;  
              // 修改size为w  
                size = w;  
                modified = true;  
            }  
        }  
        return modified;    
    }  
    

    说明:根据complement值,将ArrayList中包含c中元素的元素删除或者保留,被removeAll(collection<?> c)和retailAll(collection<?> c)两个方法调用

    (28)removeAll(collection<?> c)

     public boolean removeAll(Collection<?> c) {  
     // 如果c为空,则抛出空指针异常  
        Objects.requireNonNull(c);  
     // 调用batchRemove移除c中的元素  
        return batchRemove(c, false);  
    }  
    

    说明:ArrayList移除c中的所有元素

    (29)retainAll(collection<?> c)

     public boolean retainAll(Collection<?> c) {  
    Objects.requireNonNull(c);  
     // 调用batchRemove保留c中的元素  
    return batchRemove(c, true);  
    } 
    

    说明:和removeAll相反,仅保留c中所有的元素

    (30)iterator()

     public Iterator<E> iterator() {
        return new Itr();
    }
    

    说明:返回一个Iterator对象,Itr为ArrayList的一个内部类,其实现了Iterator接口

    (31)listIterator()

     public ListIterator<E> listIterator() {
        return new ListItr(0);
    }
    

    说明:返回一个ListIterator对象,ListItr为ArrayList的一个内部类,其实现了ListIterator接口

    (32)listIterator(int index)

     public ListIterator<E> listIterator(int index) {
        if (index < 0 || index > size)
            throw new IndexOutOfBoundsException("Index: "+index);
        return new ListItr(index);
    }
    

    说明:返回一个从index开始的ListIterator对象

    (33)subList(int fromIndex,int toIndex)

     public List<E> subList(int fromIndex, int toIndex) {  
     // 检查异常  
        subListRangeCheck(fromIndex, toIndex, size);  
     // 调用SubList类的构造方法  
        return new SubList(this, 0, fromIndex, toIndex);  
    }  
    

    说明:根据两个参数,获取到一个子序列

    (34)subListRangeCheck(int fromIndex, int toIndex, int size)

     static void subListRangeCheck(int fromIndex, int toIndex, int size) {
        if (fromIndex < 0)
            throw new IndexOutOfBoundsException("fromIndex = " + fromIndex);
        if (toIndex > size)
            throw new IndexOutOfBoundsException("toIndex = " + toIndex);
        if (fromIndex > toIndex)
            throw new IllegalArgumentException("fromIndex(" + fromIndex +
                                               ") > toIndex(" + toIndex + ")");
    }
    

    说明:根据输入的不合理参数抛出异常

    (35)sort(Comparator<? super E> c)

     public void sort(Comparator<? super E> c) {
        final int expectedModCount = modCount;
        Arrays.sort((E[]) elementData, 0, size, c);
        if (modCount != expectedModCount) {
            throw new ConcurrentModificationException();
        }
        modCount++;
    }
    

    说明:将列表中的值排序使用方法如下(匿名内部类):

     arrayList.sort(new Comparator<E>() {
            @Override
            public int compare(E o1, E o2) 
                return o1.compareTo(o2);//Integer使用
            }
        });
    

    (36)writeObject(java.io.ObjectOutputStream s)

     private void writeObject(java.io.ObjectOutputStream s)
        throws java.io.IOException{
        // Write out element count, and any hidden stuff
        int expectedModCount = modCount;
        s.defaultWriteObject();
        // Write out size as capacity for behavioural compatibility with clone()
        s.writeInt(size);
        // Write out all elements in the proper order.
        for (int i=0; i<size; i++) {
            s.writeObject(elementData[i]);
        }
        if (modCount != expectedModCount) {
            throw new ConcurrentModificationException();
        }
    }
    

    (37)readObject(java.io.ObjectInputStream s)

     private void readObject(java.io.ObjectInputStream s)
        throws java.io.IOException, ClassNotFoundException {
        elementData = EMPTY_ELEMENTDATA;
        // Read in size, and any hidden stuff
        s.defaultReadObject();
        // Read in capacity
        s.readInt(); // ignored
        if (size > 0) {
            // be like clone(), allocate array based upon size not capacity
            ensureCapacityInternal(size);
            Object[] a = elementData;
            // Read in all elements in the proper order.
            for (int i=0; i<size; i++) {
                a[i] = s.readObject();
            }
        }
    }
    

    (42)outOfBoundsMsg(int index)

     private String outOfBoundsMsg(int index) {
        return "Index: "+index+", Size: "+size;
    }
    

    4、内部类

    ArrayList有四个内部类,

    Itr

    其中的Itr是实现了Iterator接口,同时重写了里面的hasNext(),next(),remove()等方法;

    ListItr

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

    SubList

    其中的SubList继承AbstractList,实现了RandmAccess接口,得到子序列类内部实现了对子序列的增删改查等方法,但它同时也充分利用了内部类的优点,就是共享ArrayList的全局变量,例如检查器变量modCount,数组elementData等,所以SubList进行的增删改查操作都是对ArrayList的数组进行的,并没有创建新的数组

    ArrayListSpliterator

    并行遍历,区分于Iterator的顺序遍历

    该方法会把当前元素划分一部分出去创建一个新的Spliterator作为返回,两个Spliterator变会并行执行,如果元素个数小到无法划分则返回null

    二、ArrayList的动态扩容机制

    根据上面的ArrayList源码可知,ArrayList分三个构造函数,分别对应不同的扩容机制

    1、无参构造

    初始化的时候,elementData的数组长度为0,现在添加数据

     public boolean add(E e) {
        //确保内部容量(通过判断,如果够则不进行操作;容量不够就扩容来确保内部容量)
        ensureCapacityInternal(size + 1);  // ①Increments modCount!!
        elementData[size++] = e;//②
        return true;
    }
    

    得到最小扩容量(最小需要容量)

    private void ensureCapacityInternal(int minCapacity) {
      //如果实际存储数组 是空数组,则最小需要容量就是默认容量
        if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
            minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
        }
    
        ensureExplicitCapacity(minCapacity);
    }
    

    如果数组elementData的长度小于最小需要的容量(minCapacity)就扩容

       private void ensureExplicitCapacity(int minCapacity) {
        modCount++;
        //如果数组(elementData)的长度小于最小需要的容量(minCapacity)就扩容
        if (minCapacity - elementData.length > 0)
            grow(minCapacity);
    }
    

    扩容的核心方法

    /*
    *增加容量,以确保它至少能容纳
    *由最小容量参数指定的元素数。
    * @param mincapacity所需的最小容量
    */
    private void grow(int minCapacity) {
        // overflow-conscious code
        int oldCapacity = elementData.length;
        //>>位运算,右移动一位。 整体相当于newCapacity =oldCapacity + 0.5 * oldCapacity  
    
        int newCapacity = oldCapacity + (oldCapacity >> 1);
        if (newCapacity - minCapacity < 0)
            newCapacity = minCapacity;
    
        if (newCapacity - MAX_ARRAY_SIZE > 0)
            newCapacity = hugeCapacity(minCapacity);
        // 最重要的复制元素方法
        elementData = Arrays.copyOf(elementData, newCapacity);
    }
    

    总结:

    ArrayList在没有指定initialCapacity时就是会使用延迟分配数组空间,当第一次插入元素时才分配默认10个对象空间,下一次需要扩容的时候就会按照1.5倍增长(位运算)

    关于Arrays.copyOf(T[] original, int newLength)

        public static <T> T[] copyOf(T[] original, int newLength) {
        return (T[]) copyOf(original, newLength, original.getClass());
    }
    
    /**
        * @Description 复制指定的数组, 如有必要用 null 截取或填充,以使副本具有指定的长度
        * 对于所有在原数组和副本中都有效的索引,这两个数组相同索引处将包含相同的值
        * 对于在副本中有效而在原数组无效的所有索引,副本将填充 null,当且仅当指定长度大于原数组的长度时,这些索引存在
        * 返回的数组属于 newType 类
    
        * @param original 要复制的数组
        * @param 副本的长度
        * @param 副本的类
        * 
        * @return 原数组的副本,截取或用 null 填充以获得指定的长度
        * @throws NegativeArraySizeException 如果 newLength 为负
        * @throws NullPointerException 如果 original 为 null
        * @throws ArrayStoreException 如果从 original 中复制的元素不属于存储在 newType 类数组中的运行时类型
    
        * @since 1.6
    */
    public static <T,U> T[] copyOf(U[] original, int newLength, Class<? extends T[]> newType) {
        @SuppressWarnings("unchecked")
        T[] copy = ((Object)newType == (Object)Object[].class)
            ? (T[]) new Object[newLength]
            : (T[]) Array.newInstance(newType.getComponentType(), newLength);
        System.arraycopy(original, 0, copy, 0,
                         Math.min(original.length, newLength));
        return copy;
    }
    
    参数说明: 
    src:源对象 
    srcPos:源数组中的起始位置 
    dest:目标数组对象 
    destPos:目标数据中的起始位置 
    length:要拷贝的数组元素的数量
    public static native void arraycopy(Object src,  int  srcPos,
                                        Object dest, int destPos,
                                        int length);
    

    从代码可知,数组拷贝时调用的是本地方法 System.arraycopy() ;
    Arrays.copyOf()方法返回的数组是新的数组对象,原数组对象仍是原数组对象,不变,该拷贝不会影响原来的数组。

    2、带初始容量的构造函数

    分两种情况:

    一种是指定容量为0,指定为0的话,添加第一个元素扩容后,elementData的容量为1,继续添加元素,又需要扩容,容量变为1.5倍,所以不推荐指定为0

    第二种情况就是指定不为0,然后就直接在构造函数指定了数组容量,然后当所需的最小容量大于数组容量时就会扩容,扩容机制跟上述一样,

    三、ArrayList与LinkedList的区别

    • ArrayList是实现了基于动态数组的数据结构,LinkedList基于链表的数据结构
    • 对于随机访问get和set,ArrayList觉得优于LinkedList,因为LinkedList要移动指针
    • 对于新增和删除操作add和remove,LinkedList比较占优势,因为ArrayList要移动数据

    四、ListIterator与Iterator的详解

    在使用Java集合的时候,都需要使用Iterator。但是java集合中还有一个迭代器ListIterator,在使用List、ArrayList、LinkedList和Vector的时候可以使用。

    Iterator迭代器包含的方法

    hasNext():如果迭代器指向位置后面还有元素,则返回 true,否则返回false

    next():返回集合中Iterator指向位置后面的元素

    remove():删除集合中Iterator指向位置后面的元素

    ListIterator迭代器包含的方法

    add(E e): 将指定的元素插入列表,插入位置为迭代器当前位置之前

    hasNext():以正向遍历列表时,如果列表迭代器后面还有元素,则返回 true,否则返回false

    hasPrevious():如果以逆向遍历列表,列表迭代器前面还有元素,则返回 true,否则返回false

    next():返回列表中ListIterator指向位置后面的元素

    nextIndex():返回列表中ListIterator所需位置后面元素的索引

    previous():返回列表中ListIterator指向位置前面的元素

    previousIndex():返回列表中ListIterator所需位置前面元素的索引

    remove():从列表中删除next()或previous()返回的最后一个元素(有点拗口,意思就是对迭代器使用hasNext()方法时,删除ListIterator指向位置后面的元素;当对迭代器使用hasPrevious()方法时,删除ListIterator指向位置前面的元素)

    set(E e):从列表中将next()或previous()返回的最后一个元素返回的最后一个元素更改为指定元素e

    主要区别

    • 使用范围不同,Iterator可以应用于所有的集合,Set、List和Map和这些集合的子类型。而ListIterator只能用于List及其子类型。

    • ListIterator有add方法,可以向List中添加对象,而Iterator不能。

    • ListIterator和Iterator都有hasNext()和next()方法,可以实现顺序向后遍历,但是ListIterator有hasPrevious()和previous()方法,可以实现逆向(顺序向前)遍历。Iterator不可以。

    • ListIterator可以定位当前索引的位置,nextIndex()和previousIndex()可以实现。Iterator没有此功能。

    • 都可实现删除操作,但是ListIterator可以实现对象的修改,set()方法可以实现。Iterator仅能遍历,不能修改。

  • 相关阅读:
    Understanding about Baire Category Theorem
    Isometric embedding of metric space
    Convergence theorems for measurable functions
    Mindmap for "Principles of boundary element methods"
    Various formulations of Maxwell equations
    Existence and uniqueness theorems for variational problems
    Kernels and image sets for an operator and its dual
    [loj6498]农民
    [luogu3781]切树游戏
    [atAGC051B]Three Coins
  • 原文地址:https://www.cnblogs.com/sxkgeek/p/9426032.html
Copyright © 2020-2023  润新知