List
1、ArrayList
- 数组实现。节约空间,
- 数组有容量限制,超过限制时【原始容量 * 3/2 + 1】。System.arraycopy()复制到新数组
- 最好能给出数组大小的估值。第一次插入元素时默认创建大小为**10**的数组
- 和Vector不同,ArrayList中的操作是线程不安全的,多线程中建议Vector、CopyOnWriteArrayList
- 可以通过Collections.synchronizedList()实现线程安全
- 支持序列化,有实现java.io.Serializable接口
-
优势
- 按数组下标访问元素,如get(i)、set(i,e)的效率高
-
劣势
- 按下标插入或删除元素,如add(i,e)、remove(i),则要用System.arraycopy()来复制移动部分,效率较差。添加或删除最后一个元素则无影响
-
用法
- 构造器
- ArrayList()
- 构造一个初始容量为十的空列表
- ArrayList(Collection<? extends E> c)
- 构造一个包含指定集合的元素的列表,它们在集合的迭代器返回的顺序中返回
- ArrayList(int initialCapacity)
- 用指定的初始容量构造一个空列表
- ArrayList()
- 常用方法
- boolean add(E e)
- void add(int index, E element)
- boolean addAll(Collection<? extends E> c)
- boolean addAll(int index, Collection<? extends E> c) 【从指定位置开始插入到该列表】
- void clear()
- Object clone() 【返回实例浅拷贝,即两个引用指向同一实例】
- boolean contains(Object o)
- E get(int index)
- int indexOf(Object o)
- boolean isEmpty()
- int lastIndexOf(Object o) 【返回列表指定元素的最后一个索引】
- Iterator iterator
- E remove(int index)
- boolean remove(Object o)
- E set(int index, E element)
- int size();
- void sort(Comparator<? super E> c)
- Object[] toArray()
- 遍历
- 迭代器遍历
Integer value = null; Iterator iter = list.iterator(); while (iter.hasNext()) { value = (Integer)iter.next(); }
- for索引值遍历
Integer value = null; int size = list.size(); for (int i=0; i<size; i++) { value = (Integer)list.get(i); }
- foreach遍历
Integer value = null; for (Integer integ:list) { value = integ; }
- 迭代器遍历
- 遍历效率: for > foreach > 迭代器 ,迭代器遍历速度最慢
- 构造器
-
Array与ArrayList
操作 Array ArrayList 创建 String[] s = new String[10] ArrayList list = ArrayList<>() 访问 s[index] list.get(index) 更新 s[index] = “new” list.set(index, “new”) 大小 s.length list.size() 排序 java.util.Arrays.sort(array) java.util.Collections.sort(arraylist)
2、LinkedList
- 双向链表实现,无容量限制
- 双向链表本身占用了更多空间,每插入一个元素都要构造一个额外Node对象和额外的链表指针操作
- 继承AbstractSequentialList的双向链表。可以当作堆栈、队列、双端队列操作
- 实现List接口、Deque接口、Cloneable接口、Serializable接口
- LinkedList是非同步
- Entry是双向列表结点所对应的数据结构:含有当前结点所包含的值、上一个节点、下一个节点
-
优势
- 插入或删除元素时,修改前后结点的指针即可,不需要复制移动,但需要部分遍历链表移动到指定的位置
- 插入或删除元素为链表两头,如add()、addFirst()、removeLast(),可以省掉指针的移动
-
劣势
- 按下标访问元素,如get(i)、set(i,e),需要遍历链表到指定位置,如果i>数组代销的一半,会从末尾开始遍历
-
用法
- 构造器
- LinkedList()
- 构造一个空列表
- LinkedList(Collection<? extends E> c)
- 构造一个包含指定集合的元素的列表,它们在集合的迭代器返回的顺序中返回
- LinkedList()
- 常用方法
- boolean add(E e)
- void add(int index, E element)
- boolean addAll(Collection<? extends E> c)
- boolean addAll(int index, Collection<? extends E> c)
- void addFirst(E e) 【从此列表开始处插入指定元素】
- void addLast(E e)
- void clear()
- boolean contains(Object o)
- E get(int index)
- E getFirst()
- E getLast()
- int indexOf(Object o)
- int lastIndexOf(Object o)
- E peek() 【返回列表第一个元素,但不删除】
- E poll() 【返回列表第一个元素,并删除】
- E pop()
- void push(E e)
- E remove() 【返回第一个元素,并删除】
- E remove(int index)
- boolean remove(Object o)
- int size()
- E set(int index, E element)
- Object[] toArray()
- 遍历方法
- 迭代器遍历
for(Iterator iterator = list.iterator(); iterator .hasNext();) iterator.next();
- 快速随机遍历
int size = list.size(); for (int i=0; i<size; i++) { list.get(i); }
- forearch遍历
for (Integer temp : list);
- pollFirst()遍历
while(list.pollFirst() != null);
- pollLast()遍历
while(list.oillLast() != null);
- removeFirst()遍历
try { while(list.removeFirst() != null); } catch (NoSuchElementException e) {}
- removeLast()遍历
try { while(list.removeLast() != null); } catch (NoSuchElementException e) {}
- 迭代器遍历
- 遍历效率:removeFirst() 或 removeLast() 效率最高,单纯读取可用forearch遍历,千万不要用for随机访问LinkedList,效率感人
- 构造器
-
LinkedList作为FIFO(先进先出)队列
队列方法 等效方法 add(e) addLast(e) offer(e) offerLast(e) remove() removeFirst() poll() pollFirst() element() getFirst() peek() peekFirst() -
LinkedList作为LIFO(后进先出)栈
栈方法 等效方法 push(e) addFirst(e) pop(e) removeFirst(e) peek() peekFirst()
3、Vector
- 类似ArrayList,但是Vector是同步的
- vector是线程安全的,在vector的大多数方法都使用synchronized关键字修饰
- 当Vector的元素超过它的初始大小时,若有指定增长系数,则【原始容量+增长系数】,若没有则翻倍
- 不支持序列化
4、Stack
- 动态数组,默认容量10
- 继承于Vector,实现一个后进先出的堆栈
- 用法
- 常用方法
- boolean empty()
- E peek() 【查看栈顶元素,但不删除】
- E pop()
- E push(E item)
- int search(Object o) 【返回对象在堆栈中位置】
- 常用方法
5、CopyOnWriteArrayList
- 并发优化的ArrayList
- 基于不可变对象策略,在修改时先复制出一个数组快照来修改,改好再让内部指针指向新数组
- 因为对快照的修改对读操作来说不可见,所以读读之间、读写之间不互斥,写写之间要加锁互斥
- 复制快照成本昂贵,适合比较典型的读多写少的场景
- 虽然增加addIfAbsent(e)方法,会遍历数组来检查元素是否存在,但性能不会太好