Java集合类学习UML图——ArrayList

Java集合类学习UML图——ArrayList

ArrayList类的定义

public class ArrayList<E> extends AbstractList<E>
        implements List<E>, RandomAccess, Cloneable, java.io.Serializable

可以看出:
1.ArrayList 继承了AbstractList抽象类并且实现了List接口,所以提供了数组有关的添加、删除、修改、遍历等功能
2.ArrayList 实现了RandmoAccess接口,即提供了随机访问功能。也就是说,可以通过索引来快速获取元素对象,时间复杂度O(1),这里是与LinkedList一个显著区别。
3.ArrayList 实现了Cloneable接口,即覆盖了函数clone(),能被克隆。
总的来说:
 ArrayList是List接口的可变数组的实现。实现了所有可选列表操作,并允许包括 null 在内的所有元素。除了实现 List 接口外,此类还提供一些方法来操作内部用来存储列表的数组的大小。
 每个ArrayList实例都有一个容量,该容量是指用来存储列表元素的数组的大小。它总是至少等于列表的大小。随着向ArrayList中不断添加元素,其容量也自动增长。自动增长会带来数据向新数组的重新拷贝,因此,如果可预知数据量的多少,可在构造ArrayList时指定其容量。在添加大量元素前,应用程序也可以使用ensureCapacity操作来增加ArrayList实例的容量,这可以减少递增式再分配的数量。
 注意,此实现不是同步的。如果多个线程同时访问一个ArrayList实例,而其中至少一个线程从结构上修改了列表,那么它必须保持外部同步。

ArrayList的底层实现

 底层其实是数组的实现,保存所有元素,基本操作也都是基于数组的。

private static final int DEFAULT_CAPACITY = 10;//默认初始容量大小
private static final Object[] EMPTY_ELEMENTDATA = {};
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
//说明其底层实现是个数组
transient Object[] elementData; 

创建ArrayList对象

 ArrayList类中有3种构造函数,一个指定容量大小的构造器,一个默认容量为10的构造器以及构造一个包含指定collection的元素的列表,这些元素按照该collection的迭代器返回它们的顺序排列的。

public ArrayList(int initialCapacity) {
        if (initialCapacity > 0) {
            this.elementData = new Object[initialCapacity];
        } else if (initialCapacity == 0) {//等于0,直接返回空数组
            this.elementData = EMPTY_ELEMENTDATA;
        } else {
            throw new IllegalArgumentException("Illegal Capacity: "+
                                               initialCapacity);
        }
    }
public ArrayList() {
        this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
    }
public ArrayList(Collection<? extends E> c) {
        elementData = c.toArray();//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;
        }
    }

增、删、改、查

添加元素

 在添加元素之前,有个操作必须进行,那就是检查ArrayList有没有满,因为底层是数组就存在越界的风险。所以我们就要确保,add(),addAll()这些方法不越界。使用ensureCapacity();ensureCapcityInternal();ensureExplicitCapacity()方法。

 public void ensureCapacity(int minCapacity) {
        int minExpand = (elementData != DEFAULTCAPACITY_EMPTY_ELEMENTDATA)
            // any size if not default element table
            ? 0: 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++;//数组有改变,modCount就+1

        // overflow-conscious code  
        if (minCapacity - elementData.length > 0)
            grow(minCapacity);//使容量扩大,但不是无限制的扩大,有上线的
    }
    //这就是ArrayList的最大容量,是VMs允许的最大容量,超出这个容量会报出OutOfMemoryError信息
    private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
  //将指定元素添加到尾部
    public boolean add(E e) {
        ensureCapacityInternal(size + 1);  // Increments modCount!!增加数组容量
        elementData[size++] = e;
        return true;
    }
     //任何后续的元素移动到右边
     //在指定位置添加元素
    public void add(int index, E element) {
        rangeCheckForAdd(index);

        ensureCapacityInternal(size + 1);  // 保证数组大小
        System.arraycopy(elementData, index, elementData, index + 1,
                         size - index);         //拷贝元素从源elementData的index开始往后的所有元素,到目的elementData的index+1开始的位置
        elementData[index] = element;
        size++;//容量加1
    }
//添加一个Collection集合
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);//把a数组从0开始的numNew个元素,拷贝到elementData的size开始,newNew个
        size += numNew;
        return numNew != 0;
    }

设置元素,取元素

//根据索引取元素
public E get(int index) {
        rangeCheck(index);//检查索引是否越界

        return elementData(index);
    }
//根据索引修改元素,返回旧元素        
public E set(int index, E element) {
        rangeCheck(index);

        E oldValue = elementData(index);
        elementData[index] = element;
        return oldValue;            //返回的是先前在index位置上的旧元素
    }

移除元素

 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; // 清空,让GC回收

        return oldValue;
    }

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;
    }
/* 这个方法很有意思,首先是私有的,只给本身的类使用。说是fastRemove是因为不用边界检查,
      *也不用返回旧元素,更加快速,谁知道呢 ,其实等同于remove(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
    }
发布了35 篇原创文章 · 获赞 6 · 访问量 5万+
展开阅读全文

没有更多推荐了,返回首页

©️2019 CSDN 皮肤主题: 大白 设计师: CSDN官方博客

分享到微信朋友圈

×

扫一扫,手机浏览