JAVA集合(SE8)-ArrayList

JAVA集合(SE8)-ArrayList


概述

    早在 Java 2 中之前,Java 就提供了特设类。比如:Dictionary, Vector, Stack, 和 Properties 这些类用来存储和操作对象组。
    虽然这些类都非常有用,但是它们缺少一个核心的,统一的主题。由于这个原因,使用 Vector 类的方式和使用 Properties 类的方式有着很大不同。
    集合框架被设计成要满足以下几个目标。
    1. 该框架必须是高性能的。基本集合(动态数组,链表,树,哈希表)的实现也必须是高效的。
    2. 该框架允许不同类型的集合,以类似的方式工作,具有高度的互操作性。
    3. 对一个集合的扩展和适应必须是简单的。
概述来源:菜鸟教程(http://www.runoob.com/java/java-collections.html)

类与接口的关系

以下图片展示了主要的java集合类与接口的关系
图标说明
List与Set
Map

集合接口

Conllection

    集合层次结构中的根接口。

List

    有序集合(也称为序列)。该接口的用户可以精确控制每个元素在列表中的插入位置。用户可以通过整数索引(在列表中的位置)访问元素,并在列表中搜索元素。

Set

    不包含重复元素的集合。

Map

    将键映射到值的对象。映射不能包含重复的键;每个键最多只能映射到一个值。

集合实现类

ArrayList

以下为ArrayList源码中对该类的注释:
ArrayList是对List接口的可变大小数数组的实现,并允许所有类型的元素(包括null)。对于size,isEmpty,get,set,iterator和listIterator操作,它以常量时间运行。
每个ArrayList实例都有一个容量,容量是用于存储列表中的元素的数组的大小,它总是至少与列表大小一样大。当新的元素被添加到ArrayList中时,它的容量会自动增长。
在使用ensureCapacity操作添加大量元素之前,应用程序可以增加ArrayList实例的容量。
这可能会减少增量重新分配的数量。
请注意,此实现不是同步的。
如果多个线程并发地访问ArrayList实例,并且至少有一个线程在结构上修改了列表,那么它必须在外部同步。
(结构修改是指添加或删除一个或多个元素,或显式调整支持数组大小的任何操作;
仅仅设置元素的值不是结构修改。
这通常是通过对一些自然封装列表的对象进行同步来完成的。
如果不存在这样的对象,则应该使用集合“包装”列表。
synchronizedList方法。
这最好在创建时完成,以防止对列表的意外非同步访问:

列表=集合。
synchronizedList(新ArrayList(…));
这个类的迭代器和listIterator方法返回的迭代器是快速失败的:如果在创建迭代器之后的任何时候在结构上修改了列表,那么除了通过迭代器自己的删除或添加方法之外,迭代器将抛出一个ConcurrentModificationException异常。
因此,面对并发修改,迭代器会快速而干净地失败,而不是在将来某个不确定的时间冒险进行任意的、不确定的行为。

请注意,迭代器的快速失败行为不能得到保证,因为一般来说,在非同步并发修改的情况下不可能做出任何硬保证。
失败快速迭代器以最大的努力抛出ConcurrentModificationException。
因此,编写一个依赖于这个异常的正确性的程序是错误的:迭代器的快速失败行为应该只用于检测错误。

该类的几个属性:

1.serialVersionUID
源码:

private static final long serialVersionUID = 8683452581122892189L;

2.DEFAULT_CAPACITY
源码:

/**
     * Default initial capacity.
     */
private static final int DEFAULT_CAPACITY = 10;

该属性指定了一个初始的ArrayList的容量大小
3.EMPTY_ELEMENTDATA
源码:

/**
     * Shared empty array instance used for empty instances.
     */
private static final Object[] EMPTY_ELEMENTDATA = {};

用于空实例的共享空数组实例
4.DEFAULTCAPACITY_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 = {};

用于默认大小的空实例的共享空数组实例。我们将其与EMPTY_ELEMENTDATA区分开来,以了解在添加第一个元素时要膨胀多少。
5.elementData

/**
     * The array buffer into which the elements of the ArrayList are stored.
     * The capacity of the ArrayList is the length of this array buffer. Any
     * empty ArrayList with elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA
     * will be expanded to DEFAULT_CAPACITY when the first element is added.
     */
    transient Object[] elementData; // non-private to simplify nested class access

存储ArrayList元素的数组缓冲区。
ArrayList的容量是这个数组缓冲区的长度。当添加第一个元素时,任何elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA的空ArrayList都将扩展为DEFAULT_CAPACITY。
tips:transient是java语言的关键字,变量修饰符,如果用transient声明一个实例变量,当对象存储时,它的值不需要维持。换句话来说就是,用transient关键字标记的成员变量不参与序列化过程。
6.size

/**
     * The size of the ArrayList (the number of elements it contains).
     *
     * @serial
     */
    private int size;

ArrayList的大小(它包含的元素的数量)。
7.MAX_ARRAY_SIZE
源代码:

/**
     * 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 final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;

要分配的数组的最大大小。
一些vm在数组中保留一些头信息。
尝试分配更大的数组可能会抛出异常OutOfMemoryError:请求的数组大小超过VM限制

构造函数
/**
     * Constructs an empty list with an initial capacity of ten.
     */
    public ArrayList() {
        this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
    }
    /**
     * Constructs an empty list with the specified initial capacity.
     *
     * @param  initialCapacity  the initial capacity of the list
     * @throws IllegalArgumentException if the specified initial capacity
     *         is negative
     */
    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);
        }
    }
/**
     * Constructs a list containing the elements of the specified
     * collection, in the order they are returned by the collection's
     * iterator.
     *
     * @param c the collection whose elements are to be placed into this list
     * @throws NullPointerException if the specified collection is null
     */
    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;
        }
    }

第二个构造函数指定了ArrayList中的Object[]数组的长度。
其中第三个构造函数传入一个集合,构造出一个和传入的集合有相同元素的新集合。
具体流程:
1.将传入的集合利用toArray()拷贝一份给elementData
2.将elementData的长度赋值给size,并判断size是否为0;若为0,则将elementData赋值为EMPTY_ELEMENTDATA;若不为0,判断elementData的类型与Object[]的类型是否相同。若不相同则调用相关方法创建一个指定大小、Object[]类型的数组并返回赋值给elementData。
注意!此拷贝相当于浅拷贝

常用方法
方法全称说明
public int size()返回该集合中元素的个数
public void trimToSize()将该集合“瘦身”,并将modCount++(AbstractList中标识集合结构被修改的次数)
public boolean isEmpty()判断该集合中是否含有元素
public boolean contains(Object o)判断该集合中是否含有指定元素
public int indexOf(Object o)获取指定元素在集合中第一次出现的位置,若不存在,则返回-1
public int lastIndexOf(Object o)获取指定元素在集合中最后出现的位置,若不存在,则返回-1
public Object clone()返回这个ArrayList实例的一个浅拷贝。(元素本身不会被复制。)
public Object[] toArray()返回一个数组,该数组按正确的顺序(从第一个元素到最后一个元素)包含列表中的所有元素。(依然是浅拷贝)
public T[] toArray(T[] a)返回一个数组,该数组按适当的顺序(从第一个元素到最后一个元素)包含列表中的所有元素;返回数组的运行时类型是指定数组的运行时类型。如果列表符合指定的数组,则在其中返回该列表。否则,将使用指定数组的运行时类型和此列表的大小分配新数组。如果列表符合指定的数组,且有剩余空间(即,数组中元素个数多于列表),数组中紧跟在集合末尾的元素被设置为null
public E get(int index)返回列表中指定位置的元素
public E set(int index, E element)用指定的元素替换列表中指定位置的元素。
public boolean add(E e)将指定的元素追加到此列表的末尾。(若容量不够,追加时会按照旧列表的一半扩容)
public void add(int index, E element)将指定的元素插入到此列表中的指定位置。将当前位于该位置的元素(如果有)和随后的任何元素向右移动(将一个元素添加到它们的索引中)。(移动元素是利用System.arraycopy()方法在原列表上拷贝
public E remove(int index)删除列表中指定位置的元素。将任何后续元素向左移动(从它们的索引中减去一个)。
public boolean remove(Object o)如果指定元素存在,则从该列表中删除该元素的第一个出现项。如果列表不包含该元素,则它将保持不变
public void clear()从该列表中删除所有元素。此调用返回后,列表将为空
public boolean addAll(Collection<? extends E> c)将指定集合中的所有元素按指定集合的迭代器返回的顺序追加到此列表的末尾。如果在操作进行时修改了指定的集合,则此操作的行为未定义。(这意味着如果指定的集合是这个列表,并且这个列表是非空的,那么这个调用的行为是未定义的。)
public boolean addAll(int index, Collection<? extends E> c)从指定的位置开始,将指定集合中的所有元素插入此列表。将当前位于该位置的元素(如果有)和随后的任何元素向右移动(增加它们的索引)。新元素将按指定集合的迭代器返回的顺序出现在列表中
public boolean removeAll(Collection<?> c)从该列表中删除指定集合中包含的所有元素
public boolean retainAll(Collection<?> c)只保留此列表中指定集合中包含的元素。换句话说,从该列表中删除指定集合中不包含的所有元素
public ListIterator listIterator(int index)从列表中指定的位置开始,对该列表中的元素(以适当的顺序)返回一个列表迭代器
public ListIterator listIterator()返回列表中元素的列表迭代器(按正确的顺序)
public Iterator iterator()以适当的顺序返回列表中元素的迭代器
public List subList(int fromIndex, int toIndex)返回【fromIndex,toIndex) 的子列表视图
public void forEach(Consumer<? super E> action))
public Spliterator spliterator()如果ArrayLists是不可变的,或者在结构上是不可变的(没有添加、删除等),我们可以使用array .spliterator实现它们的spliterator。相反,在遍历过程中,我们在不牺牲性能的情况下尽可能多地检测干扰。我们主要依赖于modCounts。这些方法并不能保证检测并发性违规,而且有时对于线程内干扰过于保守,但是能够检测出足够多的问题,在实践中是值得的。为此,我们(1)延迟初始化fence和expectedModCount,直到需要提交到所检查的状态的最新点;从而提高精度。(这不适用于使用当前非延迟值创建spliterator的子列表)。(2)我们只在forEach(对性能最敏感的方法)的末尾执行一个ConcurrentModificationException检查。在使用forEach时(与迭代器相反),我们通常只能在操作之后检测干扰,而不是在操作之前。进一步的cme触发检查适用于所有其他可能违反假设的情况,例如null或太小的elementData数组(考虑到它的size()),这只可能是由于干扰而发生的。这允许forEach的内部循环在不进行任何进一步检查的情况下运行,并简化了lambda解析。虽然这确实需要许多检查,但请注意,在list.stream().forEach(a)的常见情况下,除了在forEach本身内部之外,不会在其他任何地方进行检查或其他计算。其他不常用的方法不能利用这些流线。
public boolean removeIf(Predicate<? super E> filter)确定要删除哪些元素在此阶段从筛选器谓词中抛出的任何异常都不会修改集合
public void replaceAll(UnaryOperator operator)?
public void sort(Comparator<? super E> c)排序
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值