分析源码之ArrayList 第一篇 --- 源码初步分析

来源:互联网 发布:如何更换网络节点 编辑:程序博客网 时间:2024/06/06 13:25

分析源码之ArrayList

前言:

我会根据jdk文档来写每一个方法,再和源码比较
2016-8-25 增加:本篇内容还是在不断更新
2016-8-21 新增
我在查看JDK1.8源码的时候,发现1,8的源码相比较1.6发生了一些变化,所以我重新调整了文档,考虑到在公司我使用的是1.6,在家使用的是1.8,所有我会把1.8,1.6的变化都写下来.

第一:最初框架:

我的定义:

public class newArrayList < E > {}

1.6/1.8源码定义:

public class ArrayList<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, java.io.Serializable{    private static final long serialVersionUID = 8683452581122892189L;}

先不考虑继承这些关系,将来我们等写的多了,再调整架构体系
单看serialVersionUID,
其作用可以参考:
http://swiftlet.net/archives/1268
所以考虑到这些,所以加上一个可以序列化的接口至于1L和随机数选择那个,目前存疑?
好像都可以,参考:
http://blog.csdn.net/jediael_lu/article/details/26813153
修改后:

public class newArrayList < E > implements Serializable{        private static final long serialVersionUID = 1L;}

第二:数据的存储

先定义要存放的数据,根据定义我们可以知道,ArrayList其实是动态数组,LinkList是链表
所以,很显然我们要定义一个数据用来存放数据

public class newArrayList < E > {    // 存放数据的数组    private Object[] data;}

这里留一个疑问:
?
Object[] 和 E[]
应该是数组要先定义好其大小,所以采用Object,应该没有泛型数组
?
看源码我们知道,源码在定义时采用了transient修饰符
1.6 源码:

private transient Object[] elementData;

transient修饰符参考资料
2016-8-25 13:25 增:

======================================================
有关评论区有个人的提问,我也查询了下相关资料
虽然我已经讲解完所有的在文档里面显示的31个方法的源代码(暂时除了与JDK8有关的内容)
但是有一些方法其实还未涉及,其中就包括有关序列化的内容

   /**     * Save the state of the <tt>ArrayList</tt> instance to a stream (that     * is, serialize it).     *     * @serialData The length of the array backing the <tt>ArrayList</tt>     *             instance is emitted (int), followed by all of its elements     *             (each an <tt>Object</tt>) in the proper order.     */    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();        }    }    /**     * Reconstitute the <tt>ArrayList</tt> instance from a stream (that is,     * deserialize it).     */    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();            }        }    }

但是有个疑问,我的测试代码:

  public static void main(String[] args) {        ArrayList < Integer > arr = new ArrayList < Integer >();        arr.add(1);        arr.add(2);        arr.add(3);        File file = new File("person.out");        try {            ObjectOutputStream oout = new ObjectOutputStream(new FileOutputStream(file));            oout.writeObject(arr);            oout.close();            ObjectInputStream oin = new ObjectInputStream(new FileInputStream(file));            Object newPerson = oin.readObject();            oin.close();            System.out.println(newPerson);        }        catch (Exception e) {            e.printStackTrace();        }    }//输出[1, 2, 3]

我在debug模式下,并没有看到他调用自身重写的readObjectwriteObject 代码????而且这两个代码都是私有方法.

============================================================

其上的英文注释,有一句值得注意:
the capacity of the ArrayList is the length of this array buffer.
容量,之后我们会遇到一个size属性.值得区分一下
1.8 源码:

transient Object[] elementData; // non-private to simplify nested class access

对private的去掉有一段解释,目的是为了简化对内部类的访问:暂时不考虑

第三:构造函数

目前构造函数有3种,
1.无参数 默认创建一个10位数组
2.有参数 传入一个大小Capcity
3.传入一个集合[暂先不考虑]
无参数可以用有参数的替代
我开始的写法:

newArrayList(int initalCapcity) {        this.size = initalCapcity;        this.data = new Object[initalCapcity];}

1.6源码的写法:

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

好像super()没有什么用, 暂时忽略

protected AbstractList() {}

先判断入参的正确性:
其次就是直接赋值.
这里对比,我做了一个
this.size = initalCapcity;
其实是错误的
之前我们也说过Capcity是ArrayList里面数组的length,按照源码注释就是:

The capacity of the ArrayList is the length of this array buffer.

但是size:

The size of the ArrayList (the number of elements it contains).

是数组里面包含的有效数据的个数!!!!!所以初始化的时候size是不可以赋值,或者直接复制为0;
1.8的源码:

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

其实本质上差不多,只是在入参为0的时候,增加了一个
private static final Object[] EMPTY_ELEMENTDATA = {};
原因是什么??加快速度,减小损耗?
此外,无参数的也发生了一次变化:

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

private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
这个并没有初始化为长度为10的数组,而是单纯的初始化为一个空数组.
看注释:

/** * Shared empty array instance used for empty instances. */   private static final Object[] EMPTY_ELEMENTDATA = {};
/** * Shared empty array instance used for default sized empty instances. We * distinguish this from EMPTY_ELEMENTDATA to know how much to inflate when * first element is added. */   private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};

明白了,原来初始化依然为空数组,但是在第一个数组增加的时候会扩充为10.

第四:相关操作

1. boolean add(E e)

Appends the specified element to the end of this list.

我一开始的写法:

// 增加一个新的元素public boolean add(E e) {    this.data[size++] = e;    return true;}
// 源码public boolean add(E e) {    ensureCapacity(size + 1);  // Increments modCount!!    elementData[size++] = e;    return true;}

有三个点:
1. 增加了一个保障容量的函数
2. this.data 和 直接用elementData有区别吗?
3. 有无必要返回 true ??

先看第一个,要确保当前的容量在至少增加一个的情况下可行,
所以要把当前容量+1和旧的容量作比较,旧的容量就是指Object[] data 的length.
如果不够就扩容,扩容是要复制之前旧的数组到新的数组里面
JDK源码:

public void ensureCapacity(int minCapacity) {    modCount++;    int oldCapacity = elementData.length;    if (minCapacity > oldCapacity) {        Object oldData[] = elementData;        int newCapacity = (oldCapacity * 3)/2 + 1;            if (newCapacity < minCapacity)        newCapacity = minCapacity;            // minCapacity is usually close to size, so this is a win:            elementData = Arrays.copyOf(elementData, newCapacity);    }}

modCount先不管,目前我不太清楚

  1. 扩容至3/2 倍
  2. 扩容之后还要和最小需要容量做一次比较!!!!!
  3. 没有看出oldData这个赋值有什么用?
  4. 利用Arrays.copyOf() 返回新数据.
    再看1.8的源代码,1.8的源代码就复杂多了,但是更严谨,逻辑更清楚
public boolean add(E e) {        ensureCapacityInternal(size + 1);  // Increments modCount!!        elementData[size++] = e;        return true;}

这个大致相同,主要是ensureCapacityInternal变化了:

private void ensureCapacityInternal(int minCapacity) {    if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {        minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);    }    ensureExplicitCapacity(minCapacity);}

这里我们会看到DEFAULTCAPACITY_EMPTY_ELEMENTDATA的作用了,而最小容量选的是
DEFAULT_CAPACITY 也就是10,
minCapacity 传入值
两者中的最大的一个

private void ensureExplicitCapacity(int minCapacity) {        modCount++;        // overflow-conscious code        if (minCapacity - elementData.length > 0)            grow(minCapacity);}

modCount++ 依然先不考虑
很显然比较最小的容量和当前容量的比较

private void grow(int minCapacity) {        // overflow-conscious code        int oldCapacity = elementData.length;        int newCapacity = oldCapacity + (oldCapacity >> 1);        if (newCapacity - minCapacity < 0)            newCapacity = minCapacity;        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);}

private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
依然要比较扩容后的容量和最小容量比较
这里还增加了一个比较,与Integer.MAX_VALUE - 8;
为什么要-8 注释说明的很清楚,主要是考虑到不同的JVM,有的VM会在加入一些数据头

/**  * The maximum size of array to allocate.  * Some VMs reserve some header words in an array.  * Attempts to allocate larger arrays may result in  * OutOfMemoryError: Requested array size exceeds VM limit  */
private static int hugeCapacity(int minCapacity) {    if (minCapacity < 0) // overflow        throw new OutOfMemoryError();    return (minCapacity > MAX_ARRAY_SIZE) ?        Integer.MAX_VALUE :        MAX_ARRAY_SIZE;}

当扩容后的容量大于MAX_ARRAY_SIZE,我们会去比较最小需要容量和MAX_ARRAY_SIZE做比较,如果比他大,
只能取Integer.MAX_VALUE,否则是Integer.MAX_VALUE -8
相比较1.6的源码,增加了对长度的即容量的限制,而且逻辑上也更清晰了.而且对于初始化默认长度10的数组,将容量的扩充放在了add()这一个方法内,也算是对性能的一个优化

2. void add(int index, E element)

Inserts the specified element at the specified position in this list.

public void add(int index, E element) {    rangeCheckForAdd(index);    ensureCapacityInternal(size + 1);  // Increments modCount!!    System.arraycopy(elementData, index, elementData, index + 1,size - index);    elementData[index] = element;    size++;}

考虑到是在某一个位置插入元素,这里有注意点,这里的位置是在有效数据中的位置,不是指在Object[] 中的位置
我之前一直理解有误,一直以为是在Object[]中的位置,所以,即使ArrayList只有1个数据,我也可以在第10个位置插入
但是事实是我错了,这里的位置index是指有效数据中的位置,就是指size,也就是说index是要小于size的.

看JDK源码第一行:

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

可以知道,这里的index是与size做了比较,而不是与capcity做比较,所以
1. 第一步:先比较入参
2. 第二步:与之前一样,扩容校验
3. 第三步:调用Arrays的方法进行数据移动

其实每次都要扩容的原因也是可以理解的,因为GC很有可能回收了那一部分的空间

System.arraycopy(elementData, index, elementData, index + 1,size - index);elementData[index] = element;size++;

elementDataindex位置开始的值,移动到elementDataindex+1的位置,一共移动size-index个数;

3. boolean addAll(Collection

Object[] a = c.toArray();

这样就获取到了数据.显然接下来就是扩容校验,插入数据

int numNew = a.length;ensureCapacityInternal(size + numNew); System.arraycopy(a, 0, elementData, size, numNew);size += numNew;return numNew != 0; 

拷贝数据,将数组a的数据从第0位开始,拷贝到elementData的第size个位置,一共复制numNew个数字

注意返回值,true和false是指要拷贝的集合的数据的个数是否为0

4. boolean addAll(int index, Collection

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

所以很显然,
1. 第一步是和之前一样,要对index的值进行一个校验

rangeCheckForAdd(index);
2. 然后是容量校验
int numNew = a.length;
ensureCapacityInternal(size + numNew); // Increments modCount
3. 最后复制数
+ 先移出a.length个长度
Arrays.copy(elementData,index,elementData,a.length+index,size - index);
+ 再复制入要复制的值
Arrays.copy(a,0,elementData,index,a.length);

5. void clear()

Removes all of the elements from this list.

我一开始是

public void clear(){        this.size = 0;}

JDK1.8的源码:

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

GC的工作:暂时保留

6. Object clone()

Returns a shallow copy of this ArrayList instance.

我的代码:

 public Object clone(){        Object[] o = new Object[this.size];        System.arraycopy(data, 0, o, 0, size);        return o;    }

但是测试的时候报错了:

 newArrayList arrN = new newArrayList();        arrN.add(1);        arrN.add(2);        newArrayList aN = (newArrayList) arrN.clone();        System.out.println(aN);        System.out.println(aN == arrN);Exception in thread "main" java.lang.ClassCastException: [Ljava.lang.Object; cannot be cast to collectionTest.newArrayList    at collectionTest.TestCollection.main(TestCollection.java:20)

JDK1.8的代码:

/**    * Returns a shallow copy of this <tt>ArrayList</tt> instance.  (The    * elements themselves are not copied.)    *    * @return a clone of this <tt>ArrayList</tt> instance    */    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);        }    }     protected native Object clone() throws CloneNotSupportedException;

这里有个重点:浅拷贝(shallow copy)和深拷贝(deep copy)
这里的拷贝显然只是个浅拷贝
除此以外,还有个疑问,ArrayList的父类是Object,从eclipse的继承关系上来看是这样,但是为什么
找不出extends的这一标志;

7. boolean contains(Object o)

Returns true if this list contains the specified element.

我的代码:

public boolean contains(Object o){    for (Object o1: this.data){                                                        if(!o1.getClass().getName().equals(                o.getClass().getName())){                    continue;            }        if(o1.equals(o)){            return true;        }    }    return false;}

但是JDK1.8源码

public boolean contains(Object o) {      return indexOf(o) >= 0;}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;}

要注意null这个特殊的值
我其实又犯了一个错误,应该是用size 而不是用 foreach 来循环所有的数据

8. void ensureCapacity(int minCapacity)

Increases the capacity of this ArrayList instance, if necessary, to ensure that it can hold at least the number of elements specified by the minimum capacity argument.

这个在boolean add(E e)中已经分析过了

9. void forEach(Consumer<? super E> action)

Performs the given action for each element of the Iterable until all elements have been processed or the action throws an exception.

这个方法设计JDK8的一个新特性Default 方法涉及JDK8暂时不讨论

10. E get(int index)

Returns the element at the specified position in this list.

public E get(int index) {    rangeCheck(index);    return elementData(index);}private void rangeCheck(int index) {    if (index >= size)        throw new IndexOutOfBoundsException(outOfBoundsMsg(index));}// Positional Access Operations@SuppressWarnings("unchecked")E elementData(int index) {    return (E) elementData[index];}

乍一看似乎有个BUG,就是index只是判断了大于size,并没有判断小于0.
但是我们测试了一下,发现并不是这样:
测试代码

 ArrayList arr = new ArrayList();    arr.add(1);    arr.add(2);    arr.get(-3);    System.out.println(arr);Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: -3    at java.util.ArrayList.elementData(ArrayList.java:418)    at java.util.ArrayList.get(ArrayList.java:431)    at collectionTest.TestCollection.main(TestCollection.java:29)

原因看注释:

/**    * Checks if the given index is in range.  If not, throws an appropriate    * runtime exception.  This method does *not* check if the index is    * negative: It is always used immediately prior to an array access,    * which throws an ArrayIndexOutOfBoundsException if index is negative.    */

看注释是说过在访问数组之前就会抛出异常,如果index是负的

但看这个方法,逻辑顺序符合一般的顺序,先判断入参,再进行获取数据

11.int indexOf(Object o)

Returns the index of the first occurrence of the specified element in this list, or -1 if this list does not contain the element.

/**    * Returns the index of the first occurrence of the specified element    * in this list, or -1 if this list does not contain the element.    * More formally, returns the lowest index <tt>i</tt> such that    * <tt>(o==null&nbsp;?&nbsp;get(i)==null&nbsp;:&nbsp;o.equals(get(i)))</tt>,    * or -1 if there is no such index.    */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;}

这个在contains()里面分析过.

12.boolean isEmpty()

Returns true if this list contains no elements.

我的代码:

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

JDK1.8源码:

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

13. Iterator iterator()

Returns an iterator over the elements in this list in proper sequence.

/**    * Returns an iterator over the elements in this list in proper sequence.    *    * <p>The returned iterator is <a href="#fail-fast"><i>fail-fast</i></a>.    *    * @return an iterator over the elements in this list in proper sequence    */public Iterator<E> iterator() {    return new Itr();}

暂先不考虑,看源码涉及不少JDK8的知识

14.int lastIndexOf(Object o)

Returns the index of the last occurrence of the specified element in this list, or -1 if this list does not contain the element.

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

indexOf差不多,注意:开始元素是size-1

15. ListIterator listIterator()

Returns a list iterator over the elements in this list (in proper sequence).

16. ListIterator listIterator(int index)

Returns a list iterator over the elements in this list (in proper sequence), starting at the specified position in the list.

17. E remove(int index)

Removes the element at the specified position in this list.

/**    * Removes the element at the specified position in this list.    * Shifts any subsequent elements to the left (subtracts one from their    * indices).    *    * @param index the index of the element to be removed    * @return the element that was removed from the list    * @throws IndexOutOfBoundsException {@inheritDoc}    */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;}

删除后多余的数组内容会被置为null

18. E remove(int index)

Removes the element at the specified position in this list.

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

从这里我们可以总结出当数组的值值为null时,GC会发挥其作用。
之所以用fastRemove而不是用Remove(index)
注释有解释

Private remove method that skips bounds checking and does not return the value removed.

简单来说就是不需要做边界校验,不需要返回被删除的值

19. boolean removeAll(Collection

private boolean batchRemove(Collection<?> c, boolean complement) {        final Object[] elementData = this.elementData;        int r = 0, w = 0;        boolean modified = false;        try {            for (; r < size; r++)                if (c.contains(elementData[r]) == complement)                 elementData[w++] = elementData[r];        } finally {            // Preserve behavioral compatibility with AbstractCollection,            // even if c.contains() throws.            if (r != size) {                System.arraycopy(elementData, r,                                 elementData, w,                                 size - r);                w += size - r;            }            if (w != size) {                // clear to let GC do its work                for (int i = w; i < size; i++)                    elementData[i] = null;                modCount += size - w;                size = w;                modified = true;            }        }        return modified;}

这个方法通过complemet来过滤数据,这里的数据操作都是在同一个数组内,这个是关键.对于符合条件的数据,依次重新放入数组
如果c.contains()有异常,那么此时for循环没有进行到底,所以有r!=size,如果有这种情况,拷贝数组,将未处理的数据拷贝到
已经处理好的数据的后面,所以现在的数据包括出现异常前的数据,和出现异常后的未处理的所有数据.修改w的值
如果数组数据发送变化,就会有w!=size,那么多余的数据置为null,那么gc会工作,修改sizemodified.所以这个函数返回的是根
据当前数组有无变化决定的.

20.boolean removeIf(Predicate<? super E> filter)

Removes all of the elements of this collection that satisfy the given predicate.

21. protected void removeRange(int fromIndex, int toIndex)

Removes from this list all of the elements whose index is between fromIndex, inclusive, and toIndex, exclusive.

removeRange()protected方法

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

其实现在看起来都是System.arraycopy这个函数在发挥作用,增加,删除都涉及到这个函数
不出意外,他是个本地方法:

public static native void arraycopy(Object src,  int  srcPos,                                    Object dest, int destPos,                                    int length);

22. void replaceAll(UnaryOperator operator)

Replaces each element of this list with the result of applying the operator to that element.

23. boolean retainAll(Collection

 public boolean retainAll(Collection<?> c) {        Objects.requireNonNull(c);        return batchRemove(c, true);    }

类似两个集合做差集.

24.E set(int index, E element)

Replaces the element at the specified position in this list with the specified element.

    /**     * Replaces the element at the specified position in this list with     * the specified element.     *     * @param index index of the element to replace     * @param element element to be stored at the specified position     * @return the element previously at the specified position     * @throws IndexOutOfBoundsException {@inheritDoc}     */    public E set(int index, E element) {        rangeCheck(index);        E oldValue = elementData(index);        elementData[index] = element;        return oldValue;    }

25.int size()

Returns the number of elements in this list.

 public int size() {        return size;    }

26.void sort(Comparator

27.Spliterator spliterator()

Creates a late-binding and fail-fast Spliterator over the elements in this list.

28.List subList(int fromIndex, int toIndex)

Returns a view of the portion of this list between the specified fromIndex, inclusive, and toIndex, exclusive.

 public List<E> subList(int fromIndex, int toIndex) {        subListRangeCheck(fromIndex, toIndex, size);        return new SubList(this, 0, fromIndex, toIndex);    }    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 + ")");    }

29.Object[] toArray()

Returns an array containing all of the elements in this list in proper sequence (from first to last element).

 /**     * Returns an array containing all of the elements in this list     * in proper sequence (from first to last element).     *     * <p>The returned array will be "safe" in that no references to it are     * maintained by this list.  (In other words, this method must allocate     * a new array).  The caller is thus free to modify the returned array.     *     * <p>This method acts as bridge between array-based and collection-based     * APIs.     *     * @return an array containing all of the elements in this list in     *         proper sequence     */    public Object[] toArray() {        return Arrays.copyOf(elementData, size);    }

从注释看,这个将会返回一个数组,这个数组是重新开辟内存空间的,所以你可以尽情的去操作它.
这个方法很重要,它是连接数组为基础和集合为基础的数据的桥梁.
测试一下

ArrayList<Integer> arr = new ArrayList<Integer>();    arr.add(1);    arr.add(2);    arr.add(3);    Object[] o = arr.toArray();    arr.add(4);    for(Object a : o){        System.out.println(a);    }//output:123

30. T[] toArray(T[] a)

Returns an array containing all of the elements in this list in proper sequence (from first to last element); the runtime type of the returned array is that of the specified array.

@SuppressWarnings("unchecked")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;}

看了好久没看出区别,难道就是有参数的增加了一个类型,可以初始化一个有参数的数组
,类型为传入的????

31.void trimToSize()

Trims the capacity of this ArrayList instance to be the list’s current size.

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

这里有个运算顺序,是先计算赋值符号右边的内容

暂先统计一下,目前遇到的一些未能解决的问题:
1.debug模式下,并没有看到他调用自身重写的readObject和writeObject 代码????而且这两个代码都是私有方法.这个是在那个地方调用的?

2.ArrayList的父类是Object,从eclipse的继承关系上来看是这样,但是为什么
找不出extends的这一标志;

3.为什么访问数组之前就会抛出异常,如果index是负的.详细 10 E get(int index),这里的异常实在那里抛出的?

4.T[] toArray(T[] a)的正确用法

0 0
原创粉丝点击