一、Collections接口
Java中,集合类的基本接口是Collection接口,这个接口有两个基本方法:
public interface Collection<E> {
boolean add(E element);
Iterator<E> iterator();
...
}
add方法用于向集合中添加元素。若添加元素确实改变了集合就返回true,若集合没有发生变化就返回false。
集合有两个基本接口:Collection和Map
二、常用的集合
2.1 ArrayList
ArrayList是一个实现了List接口的类,它也实现了RandomAccess接口,支持高速的随机访问,因此使用get()方法的效率很高。
ArrayList有一个重大的缺陷:从数组的中间位置删除一个元素需要付出很大的代价,其原因是数组中处于被删除元素之后的所有元素都要向数组的前端移动。在数组的中间插入元素同理。为解决这一缺陷,可以使用LinkedList。
2.2 LinkedList
LinkedList同样是一个实现了List接口的类,它解决了向ArrayList中插入和从ArrayList中删除元素的内存移动问题。
在Java中,所有链表实际上都是双向链接(doubly linked),即每个结点都存放着后继节点和前驱结点的引用。使用LinkedList时,向数组中插入结点和删除数组中的结点就很轻松,只需要改变对应元素前后的结点的引用即可。
LinkedList的缺点是没有实现RandomAccess接口,即不支持高速的随机访问,如下代码是十分低效的:
for (int i = 0; i < list.size(); i++) {
// do something with list.get(i);
}
使用上述方式来访问LinkedList中的元素时,每次循环都会从链表的头部开始,一步步走到第i个元素。处理这种问题的方法是使用迭代器来对LinkedList中的内容做循环。
2.3 HashSet
HashSet根据对象的hashCode,把对象散列到桶(bucket)中。每一个桶都是一个链表,保存了所有散列到这个桶中的元素。
注意:使用迭代器遍历HashSet时,元素出现的顺序几乎是随机的。
2.4 TreeSet
TreeSet与HashSet十分相似,但它是一个有序集合(Sorted Collection),可以以任意顺序将元素插入到集合中。在对集合进行遍历时,每个值将自动地按照排序后的顺序呈现。由于排序过程需要对元素做比较,因此要么TreeSet中的元素实现了Comparable接口,要么需要在创建这个TreeSet的同时传入一个Comparator,指定排序的方式。
TreeSet使用红黑树实现。将一个元素添加到HashSet中要比添加到HashSet中更慢,因为TreeSet是树结构,插入过程约为O(log2(n))的时间复杂度,其中n是TreeSet中已有的元素数。
2.5 队列Queue与双端队列Deque
队列允许用户在尾部添加或删除元素,双端队列允许用户在头部和尾部添加或删除元素。对应的接口分别为Queue<E>和Deque<E>。ArrayDeque和LinkedList这两个类都实现了Queue和Deque接口,且在必要时可以增加队列的长度。
2.6 优先级队列PriorityQueue
优先级队列内部使用堆实现。默认使用小顶堆,即最小的元素位于堆顶。与TreeSet同样地,插入优先级队列的元素需要实现Comparable接口,或者在构造优先级队列时要提供Comparator。
三、映射(Map)
3.1 HashMap
HashMap类实现了Map接口。它对键进行散列,并把键值对存入对应的bucket中。
3.2 TreeMap
TreeMap同样实现了Map接口。它用键的整体顺序对元素进行排序,并将其组织成搜索树。
3.3 映射视图
Map本身并不是Collection,但是可以得到Map的视图(view)——这是实现了Collection接口或某个子接口的对象。
有3种视图:键集keySet、值集合values和键/值对集entrySet:
Set<K> keySet()
Collection<V> values()
Set<Map.Entry<K, V>> entrySet()
如果在keySet视图上调用迭代器的remove方法,实际上会从Map种删除这个键和与它关联的值。不过,不能向keySet增加元素。