JDK源码走读(3):容器之ArrayList

原创 2017年01月03日 11:30:47

本章分析List系列中的ArrayList,有些与PriorityQueue类似,比如底层同样采取数组存储元素,也涉及到扩容操作等;也有不同之处,比如PriorityQueue不允许存入的元素为null,而ArrayList允许将null元素存放其中。

一、 类实现/继承体系结构

为了对整个List实现/继承体系有个全貌,先将体系结构图画出来:

二、 关键数据成员

(1)存储结构

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

以数组作为底层存储结构,存放ArrayList链表中的元素

数组elementData的默认初始化大小(DEFAULT_CAPACITY)是10。

(2)数组存放的元素个数

private int size;

三、 构造函数

ArrayList提供了多种形式的构造函数,在此不一一列举,就参数来说,主要包括,数组链表(elementData)初始化大小(initialCapacity)值、其他集合

这里要讲下以下几个构造函数:

publicArrayList (Collection<? extends E> c):利用另一个集合初始化ArrayList,要求就是负责初始化集合中的元素类型是E或者是E的子类。

四、 一些链表操作

(1)  void trimToSize():将ArrayList的存储空间压缩到size大小,将空闲空间还给系统

做法就是Arrays.copyOf(elementData, size)新生成一个数组,赋值给elementData;

(2)  void sort(Comparator<? super E> c):对链表进行排序,调用了Arrays.sort接口

Arrays.sort((E[])elementData, 0, size, c);

这里有一点,因为ArrayList接口都不是线程安全的,在一个线程操作链表时,并不能防止其他线程也在操作链表,有可能在排序时,其他线程已经修改了链表,修改有可能导致排序结果不准确,所以,这时就需要抛出异常:

public void sort(Comparator<?super E> c) {

    final int expectedModCount = modCount;

    Arrays.sort((E[]) elementData, 0, size, c);

    if (modCount != expectedModCount) {

            throw newConcurrentModificationException();

        }

        modCount++;

    }

五、 增

(1)  boolean addAll(Collection<? extends E> c):将容器c中元素添加到ArrayList的末尾

首先检查容量capacity,然后执行拷贝

        Object[] a = c.toArray();

        int numNew = a.length;

        ensureCapacityInternal(size +numNew);  // Increments modCount

        System.arraycopy(a, 0, elementData,size, numNew);

        size += numNew; 

System.arraycopy参数含义:

第一个参数:数据来源数组;

第二个参数:数据来源数组的起始拷贝索引index;

第三个参数:数据目标数组;

第四个参数:数据目标数组起始拷贝索引index;

第五个参数:拷贝元素的个数;

(2)  boolean addAll(int index, Collection<?extends E> c):将容器c中元素添加到ArrayList中,添加的起始位置是在index处

如果index不是数组末尾,就涉及到两次拷贝:

if (size - index > 0)
    System.arraycopy(elementData,index, elementData, index+numNew, numMoved);                          
    System.arraycopy(a,0, elementData, index, numNew);

六、 删

(1)  E remove(int index):删除位于index位置的元素

不可避免的,会将数组elementData 在index之后元素前移一个位置,复杂度O(n)

System.arraycopy(elementData,index+1, elementData, index, numMoved);

(2)  boolean removeAll(Collection<?> c):删除ArrayList中的集合c中的元素,即求交集

这里使用了一个叫做batchRemove的私有函数:

    private booleanbatchRemove(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 behavioralcompatibility 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;

    }

七、 改

八、 查

peek():返回队列queue中index=0的元素,queue[0];如果为空,则返回null。

contains(Object o):

public booleancontains(Object o) {

        return indexOf(o) != -1;

}

九、 遍历

ArrayList实现了内部类Itr:

private class Itrimplements Iterator<E>

ArrayList还实现了内部类ListItr,其继承自Itr,并实现了接口ListIterator:

private class ListItrextends Itr implements ListIterator<E>

而接口ListIterator继承自Iterator接口:interface ListIterator<E>extends Iterator<E>

所以,可以通过两种迭代器遍历ArrayList,分别对应到Itr和ListItr:

Iterator<String>iter = names.iterator();

ListIterator<String>iter = names.listIterator()/names.listIterator(1);

 Itr就是通用的迭代器,提供hasNext和next接口:

public Iterator<E> iterator() {

        return new Itr();

}

ListIterator针对ArrayList,除了提供hasNext和next接口,还提供遍历的起始点index,并且还可以逆序遍历:

   public ListIterator<E> listIterator()/listIterator(index) {
        return new ListItr(0)/ListItr(index);
   }
   ListIterator<String> iter = names.listIterator(3);
   while (iter.hasPrevious()) {
      System.out.println(iter.previous());
   }

十、 子链表subList

ArrayList实现了List<E>subList(int fromIndex, int toIndex)

List<E>subList(int fromIndex, int toIndex)接口即返回一个新生成的子链表subList对象。

版权声明:本文为博主原创文章,未经博主允许不得转载。

相关文章推荐

Java容器深入研究(jdk 1.8)--- ArrayList总结与源码分析

结构: public class ArrayList extends AbstractList         implements List, RandomAccess, Cloneable, ja...

ArrayList源码解析 给jdk写注释系列之jdk1.6容器(1)

原文出处: 吞噬天帝 工作中经常听到别人讲“容器”,各种各样的容器,话说到底什么是容器,通俗的讲“容器就是用来装东西的器皿,比如:水桶就是用来盛水的,水桶就是一个容器。” ok,在我们写程序的时候...

JDK源码学习(3)-java.util.ArrayList与LinkedList

list的源码解析

给jdk写注释系列之jdk1.6容器(1):ArrayList源码解析

给jdk写注释系列之jdk1.6容器(2):LinkedList源码解析 给jdk写注释系列之jdk1.6容器(3):Iterator设计模式 给jdk写注释系列之jdk1.6容器(4)-Hash...

59_数组_模拟ArrayList容器的底层实现_JDK源码分析ArrayList

模拟ArrayList容器的底层实现_JDK源码分析ArrayList

JDK源码走读(4):容器之LinkedList

本章分析List系列中的LinkedList,真正意义上的链表,底层采用链表形式存储数据元素。LinkedList是一个双向链表,可以向前或向后两个方向遍历链表。LinkedList也可以存放null...
  • shawhe
  • shawhe
  • 2017年01月19日 17:27
  • 107

ArrayList源码Jdk1.8

  • 2015年10月29日 20:10
  • 54KB
  • 下载

ArrayList源码分析(含jdk1.8).pdf

  • 2017年04月24日 08:49
  • 632KB
  • 下载

Java8源码-ArrayList

相信大家对ArrayList的使用已经很熟悉了,但你真的了解ArrayList吗?ArrayList是如何实现可变长的?ArrayList有哪些私有方法?它们对ArrayList的功能起到了什么作用?...

Java容器类源码学习笔记之ArrayList

注意:我用的JDK版本是1.8, 本系列博客主要是记录自己读Java集合类源码的笔记,该笔记只记录了每个集合类部分方法,也是生产环境经常的用到的,主要是增删改查操作。如果不对的地方,还请广大网友及时指...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:JDK源码走读(3):容器之ArrayList
举报原因:
原因补充:

(最多只允许输入30个字)