list接口:
1>元素有序(插入有序),元素可重复( 可重复的更确切概念即e1.equals(e2) )。
2>如果列表本身允许null元素的话,允许多个null值。
3>list借口提供了特殊的迭代器ListIterater,除了允许Iterater接口提供正常的操作外,该迭代器还允许元素插入和替换,以及双向访问,还提供了一个方法来获取从列表中指定位置开始的列表迭代器。( ListIterater(int index)
常见实现类:ArrayList,LinkedList,Vector,stack
1. ArrayList:
(1)ArrayList内部封装了一个长度可变的数组对象。每个 ArrayList 实例都有一个容量,该容量是指用来存储列表元素的数组的大小,他总是至少等于列表的大小。随着向 Arraylist 中不断添加元素,其容量也自动整长。
(2)线程不同步。如果多个线程同时访问一个ArrayList实例,而其中一个线程从结构上修改了列表,那么它必须保持外部同步。同步一般通过1.对自然封装该列表的对象进行同步操作来完成。2.如果不存在这样的对象,则应该使用Collections.synchronizedList方法在创建时将该列表“包装”起来,以防止意外对列表进行不同步的访问。
List list=Collections.synchronizedList(new ArrayList());
(3)ArrayList 存/取元素效率非常的高(get/set),时间复杂度是O(1),而查找,插入和删除元素效率不太高,时间复杂度为O(n)。由于 ArrayLIst 集合的底层是使用一个数组来保存元素。在增加或删除指定位置的元素时,会导致创建新的数组,效率比较低,但这种数组的结构允许程序通过索引的方式来访问元素,因此查找元素很便捷(时间复杂度为O(N))。
2. LinkedList:
(1)LinkedList 集合内部维护了一个双向循环链表。链表中的每一个元素都使用引用的方式来记住它的前一个元素和后一个元素,从而可以将所有的元素彼此连接起来。
(2)线程不同步。如果多个线程同时访问一个链接列表,而其中一个线程从结构上修改了列表,那么它必须保持外部同步。同步一般通过1.对自然封装该列表的对象进行同步操作来完成。2.如果不存在这样的对象,则应该使用Collections.synchronizedList方法在创建时将该列表“包装”起来,以防止意外对列表进行不同步的访问.
List list=Collections.synchronizedList(new LinkedList());
(3)LinkedList 增删效率高,查询效率低下。ArrayList 所有操作都是按照双重链接列表的需要执行的。在列表中编索引的操作将从开头或结尾遍历列表。而当插入一个新元素时,只需要修改元素之间的这种引用关系即可,删除一个节点也是如此。
3. Vector:
其用法类似 ArrayList ,就不多说重复了。
区别于 ArrayList的是“Vector是线程安全的”。然而,Vector真是线程安全的吗? 我们说的Vector线程安全是因为Vector的所有方法都有synchronized修饰,然后这并不意味着它就线程安全了。当进行复合操作时,如
if(!vec.contains(element)){
vec.add(element);
}
此时程序并不是线程安全的,因为判断element是否在列表里跟列表添加element元素可能同时进行。解决此问题的办法可以为此方法同步,即
if(!vec.contains(element){
synchronized(this){
vec.add(element);
}
}
如此看来,Vector并不是真正线程安全的,而且由于方法都用了synchronized修饰,反而大大降低了运行效率。还不如用加锁的ArrayList。
4. stack
stack 类表示后进先出(LIFO)的对象堆栈。它通过五个操作类 Vector 进行了扩展,允许将向量视为堆栈。它提供了通常的 push 和 pop 操作,以及取堆栈顶点的 peek 方法、测试堆栈是否为空的 empty 方法、在堆栈中查找项并确定到堆栈顶距离的 search 方法。
Deque
接口及其实现提供了 LIFO 堆栈操作的更完整和更一致的 set,应该优先使用Deque,而非此类。例如:
Deque<Integer> stack=new ArrayDeque<Integer>();