ArrayList源码分析(jdk1.8)

简介: <p><span style="font-size:14px"><span style="white-space:pre"></span><span style="white-space:pre"></span>前几天自我学习了ArrayList的源码,写了篇云笔记,现将其发布到博客,供大家学习交流,本人并非大神,如有任何问题,欢迎批评指正。</span></p> <p><span st

前几天自我学习了ArrayList的源码,写了篇云笔记,现将其发布到博客,供大家学习交流,本人并非大神,如有任何问题,欢迎批评指正。

最初是看了这篇文章http://www.cnblogs.com/hzmark/archive/2012/12/20/ArrayList.html,不过是基于jdk1.6的,遂自己分析源码并写下此文,在此表示感谢。转载请注明出处,谢谢,http://blog.csdn.net/u010887744/article/details/49496093。



ArrayList源码Jdk1.8下载

接口

特性

实现类

实现类特性

成员要求

List

线性、有序的存储容器,可通过索引访问元素

ArrayList

数组实现,非同步。


Vector

类似ArrayList,同步


LinkedList

双向链表,非同步。


         ArrayList就是动态数组,是Array的复杂版本,动态的增加和减少元素,实现了ICollection和IList接口,灵活的设置数组的大小。实现了所有可选列表操作,并允许包括 null 在内的所有元素。除了实现 List 接口外,此类还提供 一些方法来操作内部用来存储列表的数组的大小。
1、ArrayList的定义
1)所属包:package java.util;
2)导入包:
import java.util.function. Consumer;
import java.util.function. Predicate;
import java.util.function. UnaryOperator;

3)定义:
public class ArrayList<E> extends  AbstractList<E>
        implements  List<E>,  RandomAccessCloneablejava.io.Serializable

由ArrayList<E>可知其支持泛型

AbstractList提供了List接口的默认实现(个别方法为抽象方法)。

    List接口(extends Collection)定义了列表必须实现的方法。

    RandomAccess是一个标记接口,接口内没有定义任何内容。

    实现了Cloneable接口的类,可以调用Object.clone方法返回该对象的浅拷贝

    通过实现 java.io.Serializable 接口以启用其序列化功能。未实现此接口的类将无法使其任何状态序列化或反序列化。序列化接口没有方法或字段,仅用于标识可序列化的语义。


2、 ArrayList的属性

private static final long serialVersionUID = 8683452581122892189L;

private static final int DEFAULT_CAPACITY = 10; // 容纳能力

private static final Object[] EMPTY_ELEMENTDATA = {};

private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};

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

private int size//实际包含元素的个数

private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;

private static final int MAX_ARRAY_SIZE = 2147483639; //反编译的源码是这个,why??

默认容量为10;
EMPTY_ELEMENTDATA[] 构建空集合;
elementData存储ArrayList内的元素;
size表示包含的元素的数量。
最大容量2147483639,注 2147483647=2^31-1 = 2^0+2^1+……+2^30=Interger.Max_Value, 相差8是个什么鬼

3、关键字transient
        Java的serialization提供了一种持久化对象实例的机制。当持久化对象时,可能有一个特殊的对象数据成员,我们不想用serialization机制来保存它。为了在一个特定对象的一个域上关闭serialization,可以在这个域前加上关键字transient。
        transient是Java语言的关键字,用来表示一个域不是该对象串行化的一部分。当一个对象被串行化的时候,transient型变量的值不包括在串行化的表示中,然而非transient型的变量是被包括进去的。
        被标记为transient的属性在对象被序列化的时候不会被保存,这个字段的生命周期仅存于调用者的内存中而不会写到磁盘里持久化
详见另一篇笔记《 Java transient关键字使用小记
transient 例子:
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
publicclass TestTransient {
    public static void main(String[] args) throws FileNotFoundException, IOException, ClassNotFoundException {
        A a = new A(25, "张三");
        System.out.println(a);
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("d://mm.txt"));
        oos.writeObject(a);
        oos.close();
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream("d://mm.txt"));
        a = (A) ois.readObject();
        System.out.println(a);
    }
}
classAimplements Serializable {
    inta;
    transient String b;
    public A(inta, String b) {
        this.a = a;
        this.b = b;
    } 
    public String toString() {
        return"a = " + a + ",b = " + b;
    }
}
a = 25,b = 张三
a = 25,b = null

4、ArrayList的构造方法
共有3个构造方法
 public ArrayList(int initialCapacity) {
        if (initialCapacity > 0) {
            this.elementData = new Object[initialCapacity];
        } else if (initialCapacity == 0) {
            this.elementData = EMPTY_ELEMENTDATA;
        } else {
            thrownew IllegalArgumentException("Illegal Capacity: "+
                                               initialCapacity);
        }
    }
/**
     * Constructs an empty list with an initial capacity of ten.
     */
    public ArrayList() {
        this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA; //容量为10
    }
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;
        }
    }

第三个构造方法则将提供的 集合转成数组返回给elementData,返回的若不是Object[]将调用Arrays.copyOf方法将其转为Object[]
Arrays的copyOf方法
public static <T,U> T[] copyOf(U[] original, intnewLength, 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));
        //System.arraycopy详见add(int index, E element)方法
        return copy;
    }

5、ArrayList方法实现

方法列表:
1

boolean add(E e)


2
void  ensureCapacity( int   minCapacity )

3
void  add( int   index , E  element )

4
boolean  addAll(Collection<?  extends  E>  c )

5
boolean  addAll( int   index , Collection<?  extends  E>  c )

6
E get( int   index )

7
Class<?> getClass()

8
void  clear()

9
void  trimToSize()

10
boolean  contains(Object  o )

11
int  indexOf(Object  o )

12
int  lastIndexOf(Object  o )

13
boolean  containsAll(Collection collection)
AbstractCollection
14
int  hashCode()
java.util. AbstractList
15
Object clone()

16
boolean  equals(Object  o )
java.util.AbstractList
17
boolean  remove(Object  o )

18
E  remove(int  index)

19
protected   void  removeRange( int   fromIndex ,  int   toIndex )

20
boolean  removeAll(Collection <?> c)

21
boolean retainAll (Collection<?> c)

22
E set (int index , E element)

23
Object[]  toArray()

24
<T>  T[]  toArray(T[]  a)

25
void sort(Comparator<? super E> c)

26
int  size()

27
 List<E> subList(int  fromIndex , int  toIndex)


1)、add(E e)方法
public boolean add(E e) {
        // jdk1.6是ensureCapacity(size + 1)
        ensureCapacityInternal(size + 1);  // Increments modCount!!
        elementData[size++] = e;
        return true;
    }
        调用 ensureCapacityInternal至少将elementData的容量增加了1,所以 elementData[size]不会出现越界的情况。
     add(E e)都知道是在尾部添加一个元素,如何实现的呢?
    ArrayList基于数组实现的,属性中也看到了数组,具体是怎么实现的呢?比如就这个添加元素的方法,如果数组大,则在将某个位置的值设置为指定元素即可,如果数组容量不够了呢?具体实现如下:
注:ensureCapacityInternal在Arraylist中多次使用,着重理解。
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) 
      // 超出了数组可容纳的长度,则进行动态扩展
//个人理解:elementData每次扩展为1.5倍,当minCapacity达到临界值,上式if成立
            grow(minCapacity);
    }

<span style="font-family: Consolas;"></span><pre name="code" class="java" style="font-size: 15px; line-height: 21px;"><span style="font-family: Consolas; background-color: rgb(255, 255, 51);"><strong>动态扩展核心</strong></span>

 
 
<pre name="code" class="java">private void grow(int minCapacity) { // 动态扩展核心
        // overflow-conscious code
   int oldCapacity = elementData.length;
   int newCapacity = oldCapacity + (oldCapacity >> 1);//1.5倍(15 >> 1=7)
        // 再次判断新数组的容量够不够
        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 int hugeCapacity(int minCapacity) {
        if (minCapacity < 0) // overflow 溢出,貌似不可能有这种情况吧??
            throw new OutOfMemoryError();
// 也就是说minCapacity在超出最大限制时允许达到Integer.MAX_VALUE,
// 而不仅仅是Integer.MAX_VALUE-8
        return (minCapacity > MAX_ARRAY_SIZE) ?
            Integer.MAX_VALUE :
            MAX_ARRAY_SIZE;
    }
 
 

由以上源码可知:
add方法先调用ensureCapacityInternal方法增加自身容量,
如果扩容后的容量比默认的10小,那么list的容量将强制更改为默认的10,也就是说只要调用了add方法,list的容量至少为10。
        if扩容后的容量超出了数组可容纳的长度则执行grow操作,新的容量为旧的容量的1.5倍,右移操作即除以2(为什么用右移,而不直接除以2 ,这是给电脑运算的,运算的应该是二进制效率才最快,而不是给人类运算的,人类运算的才是十进制)。
        grow:如果Arraylist的容量超过默认最大值,允许其增加为Integer.MAX_VALUE,即再次增加8。
modCount:
        从类 java.util.AbstractList 继承的字段,protected transient int modCount,表示已结构上修改此列表的次数。从结构上修改是指更改列表的大小,或者打乱列表,从而使正在进行的迭代产生错误的结果。 
        在使用迭代器遍历的时候,用来检查列表中的元素是否发生结构性变化(列表元素数量发生改变)了,主要在多线程环境下需要使用,防止一个线程正在迭代遍历,另一个线程修改了这个列表的结构。使用ArrayList中的remove(int index) remove(Object o) remove(int fromIndex ,int toIndex) add等方法的时候都会修改modCount,在迭代的时候需要保持单线程的唯一操作,如果期间进行了插入或者删除,就会被迭代器检查获知,从而出现运行时异常。具体why???
ArrayList是非线程安全的。

2)void ensureCapacity(int minCapacity)

        顺带一起看一下这个方法,这个方法可供外部调用,而ensureCapacityInternal仅供内部方法(如add)调用。
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); // 具体实现见1)add方法。
        }
    }
         elementData的length要么为0,要么>=10。
        minExpand :elementData不为空则返回0,否则返回10;
1) elementData为空时 minExpand =10,如果minCapacity>10,则扩容(则length>=10),否则不进行扩容。
2) elementData非空(并假设其length=20)那么 minExpand=0,
        如果我传入的minCapacity=5>minExpand,那么将调用ensureExplicitCapacity动态扩容,但minCapacity<elementData.length,grow便不会执行了,扩容失败;
        如果我传入的minCapacity=25>minExpand,调用ensureExplicitCapacity,此时又有minCapacity>elementData.length,执行grow,扩容成功
在大致了解List大小时,可用此方法一次性增加minCapacity,这可以减少重分配次数,从而提高性能。

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

在指定位置插入指定元素。将当前处于该位置的元素(如果有的话)和所有后续元素向后移动(其索引加 1)。
①先调用rangeCheckForAdd检查索引是否合法
②合法再调用上面讲过的ensureCapacityInternal执行扩容
③调用系统的arraycopy函数将索引处及其后的元素后移一位;
④在index处插入该元素。
/**
     * A version of rangeCheck used by add and addAll.
     */
    private void rangeCheckForAdd(intindex) {
        if (index > size || index < 0)
            thrownew IndexOutOfBoundsException(outOfBoundsMsg(index));
    }
// java.lang.System
public static native void arraycopy(Object src,  int  srcPos,
                                        Object dest, intdestPos,
                                        intlength);
// src 原数组,srcPos原数组开始位置
// dest目标数组,destPos目标数组开始位置
// length:the number of array elements to be copied.即要复制的数组元素的数目

add(int index, E element)方法太耗时,主要体现在arraycopy上,一般别用。

4)addAll(Collection<? extends E> c)
public boolean addAll(Collection<? extends E> c) {
        Object[] a = c.toArray(); // 把c转化为数组a
        intnumNew = a.length;
        ensureCapacityInternal(size + numNew);  // Increments modCount
        System.arraycopy(a, 0, elementData, size, numNew);
        size += numNew;
        return numNew != 0;
    }

插入集合c(以下函数上面已经细讲了,这里只讲流程了)
①将c转换为数组a;
②调用ensureCapacityInternal动态扩容;
③调用系统函数arraycopy
④增加elementData的size
⑤有意思的小细节,numNew != 0,则返回true。// 为什么不从一开始就判断numNew的值呢,如果等于0,直接返回,后面的函数也就不用执行了?
5)addAll(int index, Collection<? extends E> c)
public boolean addAll(intindex, Collection<? extends E> c) {
        rangeCheckForAdd(index); //检查索引合法性
        Object[] a = c.toArray();
        intnumNew = a.length;
        ensureCapacityInternal(size + numNew);  // Increments modCount
        intnumMoved = size - index;
        if (numMoved > 0)
            System.arraycopy(elementData, index, elementData, index + numNew,
                             numMoved);
        System.arraycopy(a, 0, elementData, index, numNew);
        size += numNew;
        returnnumNew != 0;
    }

在指定位置插入集合c
①和add(int index, E element)一样,先调用rangeCheckForAdd检查做引合法性;
②将c转换为数组a;
③调用ensureCapacityInternal扩容;
④如果插入位置不是Arraylist的末尾,则调用arraycopy将索引及其后的元素后移;
⑤将a的元素arraycopy到elementData中;
⑥增加size
numNew != 0,则返回true

6)get(int index)

public E get(int index) {

        rangeCheck(index);

        return elementData(index);

    }

private void rangeCheck(int index) {

        if (index >= size)

            thrownew IndexOutOfBoundsException(outOfBoundsMsg(index));

    }

返回指定位置的元素
①检查索引合法性;
②返回指定数据。
7)getClass()

// 调用java.lang.Object的getClass

/*
*@return The {@code Class} object that represents the runtime
     *         class of this object.
*/

public final native Class<?> getClass();

返回当前运行的Arraylist。
8)clear()
public void clear() {
        modCount++; // 从结构上修改此列表的次数加1
        // clear to let GC do its work
        for (inti = 0; i < size; i++)
            elementData[i] = null;
        size = 0;
    }

清空Arraylist
①从结构上修改 此列表的次数加1;
②for循环将每个元素置空;
③size置为0,elementData的长度 并没有修改,如果确定不再修改list内容之后最好调用trimToSize来释放掉一些空间)。

9)trimToSize()

public void trimToSize() {
        modCount++;
        if (size < elementData.length) {
            elementData = (size == 0)
              ? EMPTY_ELEMENTDATA
              : Arrays.copyOf(elementData, size);
        } 
    }  
// package java.util;
@SuppressWarnings("unchecked")
    publicstatic <T> T[] copyOf(T[] original, intnewLength) {
        return (T[]) copyOf(original, newLength, original.getClass());
    }
public static <T,U> T[] copyOf(U[] original, intnewLength, 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));
        returncopy;
    }

        去掉预留元素的位置。   
        返回一个新数组,新数组不含null,数组的size和elementData.length相等,以节省空间。此函数可避免size很小但elementData.length很大的情况。
        ArrayList会每次增长会预申请多一点空间,1.5倍,这样就会出现当size() = 10的时候,ArrayList已经申请了15空间, trimToSize就是删除多余的5,只留10。
或许有人会有疑问:
        调用Arrays.copyOf复制size长度的元素到elementData,而且由源码看应该是从0复制到size处,那么如果我之前调用过add(int index, E element)呢?比如,list={1,2,3,null,null,4,null,null},如果调用trimToSize返回的应该是list={1,2,3,null}(因为size=4)。(我刚看这个时就这么考虑的)
        其实上面这种情况不会发生的,因为调用add(int index, E element)时,会检查index的合法性,所以list的元素肯定是相邻的,而不会出现上述这种中间出现null的情况。
10) boolean contains(Object o)
public boolean contains(Object o) {
        return indexOf(o) >= 0;
    }
判断对象o是否包含在Arraylist中。
注:不建议使用 contains(Object o)方法,看源码就知道了,调用其内置的indexOf方法,for循环一个个equals,这效率只能呵呵哒了,建议使用hashcode。

11)int indexOf(Object o)

12)int lastIndexOf(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;
    }
public int lastIndexOf(Object o) {
        if (o == null) {
            for (inti = size-1; i >= 0; i--)
                if (elementData[i]==null)
                    returni;
        } else {
            for (inti = size-1; i >= 0; i--)
                if (o.equals(elementData[i]))
                    returni;
        }
        return -1;
    }
indexOf方法:
 if (o == null)什么鬼?难道Arraylist包含了null,赶紧敲代码来压压惊。
public static void main(String[] args) {
        ArrayList arrayList = new ArrayList();
        arrayList.add(1);
        arrayList.add(1);
        arrayList.add(null);
        arrayList.add(null);
        System.out.println(arrayList.contains(null));
        System.out.println(arrayList.size());
    }
输出:
true
4
原来Arraylist不仅 可以添加null ,而且可以“随意”加!
另外,还允许存在相同的元素哦。

13)boolean containsAll(Collection collection)

判断集合A是否全部包含于集合B。
// 调用java.util.AbstractCollection的containsAll
public boolean containsAll(Collection<?> c) { // ArrayList没有此方法
        for (Object e : c)
            if (!contains(e))
                return false;
        return true;
    }
public boolean contains(Object o) { // ArrayList的方法
    return indexOf(o) >= 0; // 调用11的indexOf方法
}
// 再对比看一下package org.apache.commons.collections的containsAll
public boolean containsAll(Collection collection)
    {
        if(fast)
            return list.containsAll(collection);
        ArrayList arraylist = list;
        JVM INSTR monitorenter ;
        return list.containsAll(collection);
        Exception exception;
        exception;
        throw exception;
    } //这块源码,表示看不懂。求大神讲解

14)int hashCode()
// java.util.AbstractList
public int hashCode() {
        inthashCode = 1;
        for (E e : this)
            hashCode = 31*hashCode + (e==null ? 0 : e.hashCode());
        returnhashCode;
    }
继承 java.util. AbstractList的hashCode

15)Object clone()

/**
     * 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;
            returnv;
        } catch (CloneNotSupportedException e) {
            // this shouldn't happen, since we are Cloneable
            thrownew InternalError(e);
        }
    }

返回ArrayList实例的 浅拷贝

【浅克隆就是我们所看到的Arrays.copyOf, System.arraycopy,数组是新的,但是里面N个元素全是 引用的 旧的。】
public static void main(String[] args) {
        ArrayList List1 = new ArrayList();
        List1.add(1);
        ArrayList List2 = (ArrayList) List1.clone();
        System.out.println("未修改值(==)\t" + (List1 == List2));
        System.out.println("未修改值(equals)\t" + List1.equals(List2));
        List2.set(0, 2);
        System.out.println("list2--" + List2.hashCode() + "--" + List2.get(0));
        System.out.println("list1--" + List1.hashCode() + "--" + List1.get(0));
    }
未修改值(==)    false
未修改值(equals)    true
list2--33--2
list1--32--1
==输出为false,修改list2但list1未修改,这貌似是deepCopy啊????
其实不然,上述程序仅仅包含基本类型,没有module,

浅拷贝(影子克隆):只复制基本类型

深拷贝(深度克隆):基本类+对象


16)boolean equals(Object o)

// java.util.AbstractList
public boolean equals(Object o) {
        if (o == this)
            return true;
        if (!(o instanceof List))
            return false;
        ListIterator<E> e1 = listIterator();
        ListIterator<?> e2 = ((List<?>) o).listIterator();
        while (e1.hasNext() && e2.hasNext()) {
            E o1 = e1.next();
            Object o2 = e2.next();
            if (!(o1==null ? o2==null : o1.equals(o2)))
                return false;
        }
        return !(e1.hasNext() || e2.hasNext());
    }
        先看一下 instanceof  ,这是Java的一个关键字,一个二元操作符。作用是测试它左边的对象是否是它右边的类的实例,返回boolean类型的数据。详细见Java目录另一篇笔记《Java中的instanceof关键字》。

    ( o1 == null  ?  o2 == null  :   o1 .equals( o2 ))
如果o1==null,返回o2==null的值,如果o2恰好为null,那么返回结果为true;
如果o1!=null,返回 o1.equals(o2)的值,如果o2、o2相等,那么返回结果为tru。
注意前面还有个非“ ! ”噢。

17)boolean remove(Object o)

public boolean remove(Object o) {
        if (o == null) {
            for (int index = 0; index < size; index++)
                if (elementData[index] == null) {
                    fastRemove(index);
                    returntrue;
                }
        } else {
            for (intindex = 0; index < size; index++)
                if (o.equals(elementData[index])) {
                    fastRemove(index);
                    returntrue;
                }
        }
        returnfalse;
    }
    /*
     * Private remove method that skips bounds checking and does not
     * return the value removed.
     */
    privatevoidfastRemove(intindex) {
        modCount++;
        intnumMoved = 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(Garbage Collection) 
    }
         首先判断要remove的元素是null还是非null,然后for循环查找,核心是fastRemove(index)方法。

        fastRemove并不返回被移除的元素。
        elementData[--size] = null;因为arraycopy方法是将elementData的index+1处开始的元素往前复制,也就是说最后一个数本该消除,但还在那里,所以需要置空。如原数组{1,2,3,4},删除index=1时,首先调用arraycopy,结果为{1,3,4,4},最后一个4并没有删除。
        至于源码说的将最后一位赋值为null以便垃圾回收,个人不太理解?

18)E remove(int index)
public E remove(int index) {
        rangeCheck(index); // 检查索引合法性,详见get方法
        modCount++;
        E oldValue = elementData(index); 
        intnumMoved = size - index - 1; // 要移动的元素个数
        if (numMoved > 0)
            System.arraycopy(elementData, index+1, elementData, index,
                             numMoved);
        elementData[--size] = null; // clear to let GC do its work
        returnoldValue;
    }

删除指定位置的元素,调用的arraycopy方法前面已经讲过了。
19)void removeRange(int fromIndex, int toIndex)
protected void removeRange(intfromIndex, inttoIndex) {
        modCount++;
        intnumMoved = size - toIndex;
        System.arraycopy(elementData, toIndex, elementData, fromIndex,
                         numMoved);
        // clear to let GC do its work
        intnewSize = size - (toIndex-fromIndex);
        for (inti = newSize; i < size; i++) {
            elementData[i] = null;
        }
        size = newSize;
    }

20)boolean removeAll(Collection<?> c)

21)boolean retainAll(Collection<?> c)
**
     * Removes from this list all of its elements that are contained in the
     * specified collection.
*/
public boolean removeAll(Collection<?> c) {
        Objects.requireNonNull(c);
        return batchRemove(c, false);
    }
/**
     * Retains only the elements in this list that are contained in the
     * specified collection.  In other words, removes from this list all
     * of its elements that are not contained in the specified collection.
*/
public boolean retainAll(Collection<?> c) {
        Objects.requireNonNull(c);
        return batchRemove(c, true);
    }
// java.util.object
publicstatic <T> T requireNonNull(T obj) {
        if (obj == null)
            thrownew NullPointerException();
        returnobj;
    }
private boolean batchRemove(Collection<?> c, booleancomplement) {
        final Object[] elementData = this.elementData;
        intr = 0, w = 0; // w是重新存元素时的索引,r是原来的索引
        booleanmodified = 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 (inti = w; i < size; i++)
                    elementData[i] = null;
                modCount += size - w;
                size = w;
                modified = true;
            }
        }
        returnmodified;
    }

removeAll、retainAll:删除或保留ArrayList中包含Collection c中的的元素
首先判断集合是否为空;
核心方法batchRemove:(batch批处理),boolean complement相当精妙,代码重用!!
以removeAll为例,batchRemove(c, false),
遍历elementData,
    如果集合c中包含elementData的元素e,则c.contains(elementData[r])为true,if不成立,if结束;
    如果c不包含elementData的元素e,则if成立,将此元素e赋值给elementData[w++]【即 elementData保留了c中没有的元素,也就是删除了C中存在的所有元素】
执行finally,finally是不管try中结果如何都会执行的哦。
if (r != size),则将elementData未参加比较的元素arraycopy到elementData后面;新索引w加上刚arraycopy的数目;
if (w != size),此时w还不等于size,则将w后的元素移除,为什么移除(调用了arraycopy,详见fastRemove)。
只有执行了if (w != size)(事实上只要c中含有elementData的元素,w肯定不等于size),才modified = true,才说明remove成功,返回true,否则返回false

小例子:
public static void main(String[] args) {
        ArrayList List1 = new ArrayList();
        ArrayList List2 = new ArrayList();
        List1.add(1);
        List1.add(2);
        List1.add(3);
        List2.add(4);
        System.out.println(List1.removeAll(List2));
        for (Object object : List1) {
            System.out.println(object);
        }
    }
false
1
2
3
remove中还有一个removeIf,用的不多,这里就暂时不去分析源码了。

22)E set(int index, E element)
public E set(intindex, E element) {
        rangeCheck(index);
        E oldValue = elementData(index);
        elementData[index] = element;
        returnoldValue;
    }
在指定位置插入新的value,并返回oldValue。
23)Object[] toArray()

public Object[] toArray() {

        return Arrays.copyOf(elementDatasize);

    }

public Object[] toArray() {

        return Arrays.copyOf(elementDatasize);

    }

@SuppressWarnings("unchecked")

    publicstatic <T> T[] copyOf(T[] originalintnewLength) {

        return (T[]) copyOf(originalnewLengthoriginal.getClass());

    }

// copyOf方法详见ArrayList的第三个构造方法

此方法即将size大小的list转为数组。
24)<T> T[] toArray(T[] a)
@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;
    }
①如果传入数组的长度length小于size,返回一个新的数组,大小为size,类型与传入数组相同;
②否则将elementData的元素全部复制到传入的数组a中,并返回a;
③若length大于size,除了复制elementData外,还将把返回数组的第size个元素置为空。《只是第size个哦,其他空位不管》
25)void sort(Comparator<? super E> c)
  @Override
    @SuppressWarnings("unchecked")
    publicvoid sort(Comparator<? super E> c) {
        final int expectedModCount = modCount;
        Arrays.sort((E[]) elementData, 0, size, c);
        if (modCount != expectedModCount) {
            thrownew ConcurrentModificationException();
        }
        modCount++;
    }
       expectedModCount 初始设置为modCount, 用于记录ArrayList发生结构性改变的次数,执行完sort后去检查expectedModCount值是否和现在的modCount相等,从而保证执行sort时数据结构没有被其他进程修改,保证数据准确性。
// Arrays.sort,一直在用 Arrays.sort(arr),总算看到他兄弟的真面目了
/* @param<T> the class of the objects to be sorted
     * @param a the array to be sorted
     * @param fromIndex the index of the first element (inclusive) to be sorted
     * @param toIndex the index of the last element (exclusive) to be sorted
     * @param c the comparator to determine the order of the array.  A
     *        {@code null} value indicates that the elements'
     *        {@linkplain Comparable natural ordering} should be used.
*/
public static <T> void sort(T[] a, int fromIndex, int toIndex,
                                Comparator<? super T> c) {
        if (c == null) {
            sort(a, fromIndex, toIndex);
        } else {
            rangeCheck(a.length, fromIndex, toIndex);
            if (LegacyMergeSort.userRequested)
                legacyMergeSort(a, fromIndex, toIndex, c);
            else
                TimSort.sort(a, fromIndex, toIndex, c, null, 0, 0); //暂不分析
        }
    }
// Array的sort方法
public static void sort(Object[] a, intfromIndex, inttoIndex) {
        rangeCheck(a.length, fromIndex, toIndex); // 检查参数合法性
        if (LegacyMergeSort.userRequested)
            legacyMergeSort(a, fromIndex, toIndex);
        else
            ComparableTimSort.sort(a, fromIndex, toIndex, null, 0, 0);
    }
// Array 的 rangeCheck方法
private static void rangeCheck(intarrayLength, intfromIndex, inttoIndex) {
        if (fromIndex > toIndex) {
            thrownew IllegalArgumentException(
                    "fromIndex(" + fromIndex + ") > toIndex(" + toIndex + ")");
        }
        if (fromIndex < 0) {
            thrownew ArrayIndexOutOfBoundsException(fromIndex);
        }
        if (toIndex > arrayLength) {
            thrownew ArrayIndexOutOfBoundsException(toIndex);
        }
    }
// 这个表示看不懂
static final class LegacyMergeSort {
        privatestaticfinalbooleanuserRequested =
            java.security.AccessController.doPrivileged(
                new sun.security.action.GetBooleanAction(
                    "java.util.Arrays.useLegacyMergeSort")).booleanValue();
    }
/** To be removed in a future release. */
    privatestatic <T> void legacyMergeSort(T[] a, intfromIndex, inttoIndex,
                                            Comparator<? super T> c) {
        T[] aux = copyOfRange(a, fromIndex, toIndex);
        if (c==null)
            mergeSort(aux, a, fromIndex, toIndex, -fromIndex);
        else
            mergeSort(aux, a, fromIndex, toIndex, -fromIndex, c);
    }
// Array的copyRange方法
@SuppressWarnings("unchecked")
    publics tatic <T> T[] copyOfRange(T[] original, intfrom, intto) {
        return copyOfRange(original, from, to, (Class<? extends T[]>) original.getClass());
    }
public static <T,U> T[] copyOfRange(U[] original, intfrom, intto, Class<? extendsT[]> newType) {
        intnewLength = to - from;
        if (newLength < 0)
            thrownew IllegalArgumentException(from + " > " + to);
        @SuppressWarnings("unchecked")
        T[] copy = ((Object)newType == (Object)Object[].class)
            ? (T[]) new Object[newLength]
            : (T[]) Array.newInstance(newType.getComponentType(), newLength);
        System.arraycopy(original, from, copy, 0,
                         Math.min(original.length - from, newLength));
        returncopy;
    }
 // Array 的 mergeSort 方法
/**
     * Src is the source array that starts at index 0
     * Dest is the (possibly larger) array destination with a possible offset
     * low is the index in dest to start sorting
     * high is the end index in dest to end sorting
     * off is the offset into src corresponding to low in dest //何用?????
     * To be removed in a future release.
     */
    @SuppressWarnings({"rawtypes", "unchecked"})
    private static void mergeSort(Object[] src,
                                  Object[] dest,
                                  intlow, inthigh, intoff,
                                  Comparator c) { //off即传来的-fromIndex
        intlength = high - low;
        // Insertion sort on smallest arrays
        if (length < INSERTIONSORT_THRESHOLD) {
            for (inti=low; i<high; i++)
//没有比较器c时,代码为
//for (intj=i; j>low && ((Comparable) dest[j-1]).compareTo(dest[j])>0; j--)
                for (intj=i; j>low && c.compare(dest[j-1], dest[j])>0; j--)
                    swap(dest, j, j-1); // 源码这里新建了临时变量 Object t
            return;
        } 
        // Recursively sort halves of dest into src
        intdestLow  = low;
        intdestHigh = high;
        low  += off;
        high += off;
        intmid = (low + high) >>> 1; //
        mergeSort(dest, src, low, mid, -off, c);
        mergeSort(dest, src, mid, high, -off, c);
        // If list is already sorted, just copy from src to dest.  This is an
        // optimization that results in faster sorts for nearly ordered lists.
        
        // 没有比较器c时,代码为
        // if (((Comparable)src[mid-1]).compareTo(src[mid]) <= 0)
        if (c.compare(src[mid-1], src[mid]) <= 0) {
           System.arraycopy(src, low, dest, destLow, length);
           return;
        }
        // Merge sorted halves (now in src) into dest
        for(inti = destLow, p = low, q = mid; i < destHigh; i++) {
               //没有比较器时,为 && ((Comparable)src[p]).compareTo(src[q])<=0
            if (q >= high || p < mid && c.compare(src[p], src[q]) <= 0)
                dest[i] = src[p++];
            else
                dest[i] = src[q++];
        }
    }
26)int size()
返回实际大小size。
27)List<E> subList(int fromIndex, int toIndex)
这个方法有陷阱,详情及破解方法见另一篇笔记《 java.util.List.SubList陷阱及解决方法 》。

ps:写太多,有道云就崩溃了,不能继续写了,幸好还可以复制出来。
    再写就没有撤销功能了。。。。

转载请注明出处,谢谢,http://blog.csdn.net/u010887744/article/details/49496093。



目录
相关文章
|
3月前
|
存储 安全 Java
【JDK 源码分析】ConcurrentHashMap 底层结构
【1月更文挑战第27天】【JDK 源码分析】ConcurrentHashMap 底层结构
|
3月前
|
Java
【JDK 源码分析】HashMap 操作方法
【1月更文挑战第27天】【JDK 源码分析】HashMap Put 元素 初始化
|
4月前
|
Java
Integer类【JDK源码分析】
Integer类【JDK源码分析】
22 0
|
4月前
|
存储 网络协议 Java
【Java】BIO源码分析和改造(GraalVM JDK 11.0.19)(二)
【Java】BIO源码分析和改造(GraalVM JDK 11.0.19)
38 0
【Java】BIO源码分析和改造(GraalVM JDK 11.0.19)(二)
|
5月前
源码分析系列教程(12) - 手写Map框架(基于JDK1.7)
源码分析系列教程(12) - 手写Map框架(基于JDK1.7)
21 0
|
2月前
|
存储 网络协议 Java
【Java】BIO源码分析和改造(GraalVM JDK 11.0.19)
【Java】BIO源码分析和改造(GraalVM JDK 11.0.19)
14 0
|
3月前
|
安全 Java
【JDK 源码分析】HashMap 线程安全问题分析
【1月更文挑战第27天】【JDK 源码分析】HashMap 线程安全问题分析
|
3月前
|
存储 Java
【JDK 源码分析】HashMap 底层结构
【1月更文挑战第27天】【JDK 源码分析】HashMap 底层结构
|
8月前
|
Java API 索引
LinkedList类【JDK源码分析】
LinkedList类【JDK源码分析】
35 0
|
8月前
|
算法 搜索推荐 Java
Arrays类【JDK源码分析】
Arrays类【JDK源码分析】
33 0