List(JDK1.7)

Posted 流年素心

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了List(JDK1.7)相关的知识,希望对你有一定的参考价值。

java.util包.image

与Set不同, List允许重复的元素。即 e1.equals(e2)。

部分方法定义

  • int size();

返回列表中元素的个数,如果超过Integer.MAX_VALUE,就返回Integer.MAX_VALUE

  • boolean isEmpty();
  • boolean contains(Object o);

对于目标元素o, 如果列表中至少存在一个元素e:o==null? e==null ; o.eqauls(e)。

如果目标元素不可比较,将会抛出异常:ClassCastException.

如果目标元素为null,并且该列表不允许null元素,则抛出异常:NullPointerException.

  • Iterator<E> iterator();
  • Object[] toArray();

以恰当的顺序返回列表中的所有元素。

返回的数组是安全的,因为它的引用不是由该列表维护的。也就是说,该方法必须申请一个新的数组,即使list本身就是基于数组的。因此,调用者可以自由地修改返回的数组。

该方法作为一个桥梁,建立起基于数组和基于集合的API。

  • <T> T[] toArray(T[] a);

返回数组的运行时类型是指定的数组类型。

如果列表恰好是该类型的,就会直接返回。否则,必须申请一个新数组,新数组的大小恰好就是列表的size。

如果列表是指定类型的,并且数组中还有剩余空间,则未使用的数组位置全部置null。——这一点很有用,因为可以判断列表的长度。前提是调用者知道该list不会包含任何null元素。

  • boolean add(E e);

支持该操作的List,可能会限制允许加入该list的元素。比如,有些list可能会拒绝添加null作为元素,而其他list有可能限制元素的类型。

UnsupportedOperationException, 如果该List不支持add方法。

ClassCastException, 指定元素的类class,不允许它被添加到该list中。

NullPointerException,如果指定元素是null,并且该List不允许null元素。

IllegalArgumentException,如果该元素的某些属性,不允许它被添加到该list中。

  • boolean remove(Object o);

删除第一次出现的那个元素,即下标最小的: o==null ? get(i )==null : o.eqauls(get(i );

如果列表中不包含这样的元素,就不变。

ClassCastException,如果指定元素的类型无法与list匹配。

NullPointerException, 如果指定元素是null,并且list不允许null元素。

UnsupportedOperationException,list不支持remove方法。

  • boolean containsAll(Collection<?> c);

如果列表中包含了指定collection中的所有元素,返回true。

ClassCastException,如果指定collection中的一个或多个元素的类型与该list不匹配

NullPointerException,指定collection中包含一个或多个null,而list不允许null元素。

  • boolean addAll(Collection<? extends E> c);

UnsupportedOperationException

ClassCastException

NullPointerException

IllegalArgumentException

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

在指定的下标处插入指定collection中的所有元素。

IndexOutOfBoundsException,如果下标超出范围。

  • boolean removeAll(Collection<?> c);

删除list中所有在c中出现的元素。

  • boolean retainAll(Collection<?> c);

保留指定集合中出现的所有元素。

NullPointerException, 如果list中包含一个null,而指定的collection是不允许null的时候。

ClassCastException

  • void clear();
  • boolean equals(Object o);

两个list相等的条件是:他们包含相同的元素,以相同的顺序。

  • int hashCode();

image

  • E get(int index);
  • E set(int index, E element); //替换已有下标处的元素
  • void add(int index, E element);
  • E remove(int index);
  • int indexOf(Object o);

如果存在,就返回第一次出现的下标。如果不存在,返回-1.

  • int lastIndexOf(Object o);
  • ListIterator<E> listIterator();
  • ListIterator<E> listIterator(int index); //从指定的下标开始遍历
  • List<E> subList(int fromIndex, int toIndex);

返回一个视图。包含左下标,不包含右下标。

返回的List是基于原list的,所以在返回的list中进行的非结构性修改会在原list中体现,反之亦然。

任何针对局部范围list的操作,都可以通过传递一个subList视图来代表整个list。例如,下列语句删除了list中的部分元素:

list.subList(from, to).clear();

ArrayList

List接口的一种可调整大小的基于数组的实现。实现了所有可选的list操作,也允许所有元素,包括null。

另外,该类还提供了操纵底层实现数组的大小的方法。

该类和Vector类基本是一样的,除了ArrayList是非同步的。

以常数时间运行的方法:size, isEmpty, get, set, iterator, listIterator。摊销的常数时间,即O(n ):add。粗略来说,其他方法的运行时间都是线性的。常数因子比起LinkedList要小。

每个ArrayList的实例都有一个容量capacity。这是底层数组的大小。通常,容量至少要和List的大小一样大。因为增加一个元素有常数的摊销时间,所以没有明确规定增长策略的细节。

在增加大量元素之前扩容的一个办法是使用ensureCapacity操作,这可以减少容量调整的次数。

注意ArrayList是非同步的。如果多线程同时访问同一个ArrayList实例,并且至少有一个线程修改了列表结构,就必须要有外部的同步机制。通常通过同步某些封装了该list的对象来实现,如果没有这样的对象,该list就应该使用Collections.synchronizedList()来包装。最好在创建时就这样做,可以避免对该list的意外的非同步访问。(结构性修改是指,增加或删除一个或多个元素,或者调整了底层数组的大小,只修改了元素的值不是结构性修改)。

ArrayList中的iterator()方法和listIterator()返回的迭代器都是快速失败的。如果在创建了该迭代器之后的任意时间对list进行了结构性修改,除了通过iterator本身提供的方法之外,该Iterator都会抛出一个ConcurrentModificationException异常。面对同时发生的修改,iterator会快速干脆地失败,而不是无法确定未来的冒险的、非确定性的行为。

注意,iterator提供的快速失败机制并不能保证线程安全。快速失败机制应该只用于检测bug。

AbstractList源码

抽象类实现了部分方法。

image

 

ArrayList源码细节

ArrayList继承自AbstractList抽象类。

成员变量

image

 

构造方法

image

 

get()方法

image

image

image

 

set()方法

image

 

add()方法

image

image

 

扩容

image

 

contains()方法

image

 

remove()方法

image

 

clear()方法

image

 

clone()方法

image

 

转换为数组

image

 

迭代器 iterator 和 listIterator

image

image

image

image

【关于Itr中的remove()方法】

注意到lastRet表示上一次读取的位置,当这个位置为-1时,remove方法抛出IllegalStateException。而这个位置 为-1的情况,一个是初始化时,还未调用过next(),另一个是在调用了remove()方法后。所以,在这两种情况下是不能调用remove()方法的,即remove()方法不能连续调用,必须和next()结合,先next()后remove()。

另外,在删除元素时,会同步更新iterator中的expectedModCount,这样保持和List中的modCount的一致,从而使得checkForComodification()检测通过,本质上并不是线程同步的,当多个Iterator同时访问同一个List时,仍然是不安全的。

image

image

【ListItr】

在Itr的基础上,增加了向前遍历的方法,相当于一个双向遍历器。还增加了set()和add()方法,使得遍历器不仅可以删除元素,还可以修改和增加元素。

特别注意的,add()方法和remove()方法都会修改lastRet值为-1,因此需要读取lastRet的方法,譬如set(),remove()都不能在这两个方法后面调用,需要先调用一次next()方法。

List的add()和remove()方法都是结构性的修改,所以迭代器中的add()和remove()方法需要同步更新modCount的值,否则会在下一次增删改查操作时,检测到不相同,而抛出ConcurrentModificationException。

 

子列表视图

image

image

image

以上是关于List(JDK1.7)的主要内容,如果未能解决你的问题,请参考以下文章

List(JDK1.7)

List(JDK1.7)

使用ArrayList时代码内部发生了什么(jdk1.7)?

LinkedList源码解析(基于JDK1.7)

LinkedList源码解析(基于JDK1.7)

ArrayList源码解析(基于JDK1.7)