一、接口的API
1、Collection<E>
int size();
boolean isEmpty();
boolean contains(Object o);
Iterator<E> iterator();
Object[] toArray();
<T> T[] toArray(T[] a);//?
boolean add(E e);
boolean remove(Object o);
boolean containsAll(Collection<?> c);
boolean addAll(Collection<? extends E> c);
boolean removeAll(Collection<?> c);
boolean retainAll(Collection<?> c);//取交集
void clear();
boolean equals(Object o);
int hashCode();
2、List<E>
boolean addAll(int index, Collection<? extends E> c);
E get(int index);
E set(int index, E element);
void add(int index, E element);
E remove(int index);
int indexOf(Object o);
int lastIndexOf(Object o);
ListIterator<E> listIterator();
ListIterator<E> listIterator(int index);
List<E> subList(int fromIndex, int toIndex);
List接口继承与Collection接口。由上可见,List相比于Collection,额外提供的方法均与index有关。即List是一个有序集合,内部的每一个元素都可以通过下标直接定位。
3、Set<E>
Set提供的方法与Collection完全一致。Set规范:元素不可重复。
4、SortedSet<E>
Comparator<? super E> comparator();
SortedSet<E> subSet(E fromElement, E toElement);
SortedSet<E> headSet(E toElement);
SortedSet<E> tailSet(E fromElement);
E first();
E last();
顾名思义,有序的Set。但与LinkedHashSet不同的是,前者通过Comparator比较元素的大小来进行排序,后者则是维护元素的插入顺序。
SortedSet的这种维护是时刻维护的(就跟堆维护堆序一样),每次插入元素的时候就会根据其大小放入合适的位置。
实现类有TreeSet。
5、Queue<E>
boolean add(E e);
boolean offer(E e);
E remove();
E poll();
E element();
E peek();
队列:先进先出。注意,这里的“进”并不一定是按照时间顺序来衡量,有可能是按照其他顺序来模拟时间上的先后。
| 抛出异常 | 返回特殊值 |
插入 | ||
移除 | ||
检查 |
6、Deque<E>
void addFirst(E e);
void addLast(E e);
boolean offerFirst(E e);
boolean offerLast(E e);
E removeFirst();
E removeLast();
E pollFirst();
E pollLast();
E getFirst();
E getLast();
E peekFirst();
E peekLast();
boolean removeFirstOccurrence(Object o);
boolean removeLastOccurrence(Object o);
boolean add(E e);
boolean offer(E e);
E remove();
E poll();
E element();
E peek();
void push(E e);
E pop();
boolean remove(Object o);
boolean contains(Object o);
public int size();
Iterator<E> iterator();
Iterator<E> descendingIterator();
继承于Queue,是一个双向队列。
二、实现类
1、ArrayList<E>
public class ArrayList<E> extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable
1、ArrayList存储元素的数据结构实际上是一个数组,数组本身的大小是不可变的。因此,在向ArrayList中插入元素时,如果满足触发条件,会将ArrayList进行扩容。扩容后的数组大小通常满足:newCapacity = oldCapacity + (oldCapacity >> 1);
2、ArrayList是有最大存储容量的:
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
private static int hugeCapacity(int minCapacity) {
if (minCapacity < 0) // overflow
throw new OutOfMemoryError();
return (minCapacity > MAX_ARRAY_SIZE) ?
Integer.MAX_VALUE :
MAX_ARRAY_SIZE;
}
3、modCount??
4、在删除ArrayList中的元素后,将数组的后边的元素置为null,以使GC回收,避免内存泄漏。如:
public void clear() {
modCount++;
// clear to let GC do its work
for (int i = 0; i < size; i++)
elementData[i] = null;
size = 0;
}
5、ArrayList中对数组的操作是通过System类的
public static native void arraycopy(Object src, int srcPos,
Object dest, int destPos, int length);
执行的。
6、迭代器
7、线程不安全举例以及解决方案见Vector思考2.
2、LinkedList<E>
public class LinkedList<E>
extends AbstractSequentialList<E>
implements List<E>, Deque<E>, Cloneable, java.io.Serializable
LinkedList实现了Deque接口,是一个双向队列。
1、LinkedList的实现是建立在内部静态类
private static class Node<E> {
E item;
Node<E> next;
Node<E> prev;
Node(Node<E> prev, E element, Node<E> next) {
this.item = element;
this.next = next;
this.prev = prev;
}
}
的基础上的。
2、LinkedList是有序的,而且是双向的,可以储存重复的元素,甚至是多个null。
3、学习LinkedList的源码,发现在向LinkedList中插入、删除元素时,需时刻注意操作前后相邻两个元素关系的维护,避免“链子”断掉。对于每一个节点,不仅要维护自己的next,还要维护自己的prev。同时还要注意当前节点的next或者prev是不是null。
4、注意,向LinkedList中插入null时,只代表这个Node的item属性是null,而这个Node却一定不是null。其实,LinkedList这条由Node串联起来的“链条”根本不存在为null的Node,但是存在为Null的元素(元素只是Node的item属性)。
5、LinkedList实现了List接口,因此支持按index进行的元素的操作,但他没有实现RandomAccess,也就是说它不支持随机访问,它的按index操作实际是通过由链条的两端向中间一个一个访问实现的。
6、LinkedList实现了Deque接口,因此同时具备队列的特点,支持poll(),offer()等方法。
7、迭代器:实现很简单,看源码就行。
3、Vector<E>
public class Vector<E>
extends AbstractList<E>
Implements List<E>, RandomAccess, Cloneable, java.io.Serializable
1、Vector与ArrayList实现的接口完全一致。推断功能也会类似。
2、Vector的扩容:
int newCapacity = oldCapacity + ((capacityIncrement > 0) ?
capacityIncrement : oldCapacity);
如果没指定扩容参数,每次自动扩充一倍。
3、Vector的方法大部分被synchronized 修饰,因此Vector是线程安全的。
思考:1:ArrayList与Vector的区别在哪?
Vector是线程安全的,因此性能较低,已逐渐被弃用;而ArrayList是线程不安全的,但性能比Vector高。Vector每次扩容一倍,而ArrayList每次扩容一半。
思考2:ArrayList线程不安全举例,如何解决?
ArrayList线程不安全举例:
package com.lv.Number;
import java.util.ArrayList;
import java.util.List;
public class ArrayListInThread implements Runnable {
// 线程不安全
private List<String> threadList = new ArrayList<String>();
// 线程安全
// private List<string> threadList = Collections.synchronizedList(new
// ArrayList<string>());
@Override
public void run() {
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
// 把当前线程名称加入list中
threadList.add(Thread.currentThread().getName());
}
public static void main(String[] args) throws InterruptedException {
ArrayListInThread listThread = new ArrayListInThread();
for (int i = 0; i < 100; i++) {
Thread thread = new Thread(listThread, String.valueOf(i));
thread.start();
}
// 等待子线程执行完
Thread.sleep(2000);
System.out.println(listThread.threadList.size());
// 输出list中的值
for (int i = 0; i < listThread.threadList.size(); i++) {
if (listThread.threadList.get(i) == null) {
System.out.println();
}
System.out.print(listThread.threadList.get(i) + " ");
}
}
}
解决方式:private List<string> threadList = Collections.synchronizedList(new
ArrayList<string>());
public static <T> List<T> synchronizedList(List<T> list) {
return (list instanceof RandomAccess ?
new SynchronizedRandomAccessList<>(list) :
new SynchronizedList<>(list));
}
4、Stack<E>
public
class Stack<E> extends Vector<E>
基于Vector扩充实现了一个栈(后进先出)的数据结构。同时也具备Vector(动态数组)的功能。
5、HashSet
public class HashSet<E>
extends AbstractSet<E>
implements Set<E>, Cloneable, java.io.Serializable
基于HashMap类。
6、LinkedHashSet
基于LinkedHashMap类。
7、TreeSet
基于TreeMap类。