集合代表了一组对象(和数组一样,但数组长度不变,而集合可变;数组的元素可以是基本数据类型,但集合不可)。Java中的集合框架定义了一套规范,用来表示、操作集合,使具体的操作和实现细节解耦。可以把一个集合看成一个微型的数据库,操作不外乎“增删改查”,我们学习使用一个具体的集合实现类时,需要把这四个操作的时空复杂度弄清楚。
显然的,我们接下来的内容是围绕着集合框架的分析和实现类的描述展开的。
一、Java的集合框架
首先,请看图:
在这张图中,各个接口、抽象类、实现类之间的关系是挺复杂的,所以在下图进行了简单的划分,请看:
在A区域中,是Collection和Map的根接口,它表示Collection和Map的实现类都可以使用迭代的方式来遍历。在B、C区域中,是整个集合的两个根接口Collection和Map,下面将重点介绍这两个根接口及它们的实现类。
1、Collection
如上图所示,类主要有三个接口:
-
Set
表示不允许有重复元素的集合; -
List
表示允许有重复元素的集合; -
Queue
JDK1.5新增,与上面两个集合类主要是的区分在于Queue
主要用于存储数据,而不是处理数据。
2、Map
Map并不是一个真正意义上的集合,但是这个接口提供了三种“集合视角”(collection views ),使得可以像操作集合一样操作它们,具体如下:
- 把map的内容看作key的集合;
- 把map的内容看作value的集合;
- 把map的内容看作key-value映射的集合;
- map中键不能重复,值可以重复。
二、实现类的描述
1、Collection的实现类的描述
Arraylist和Linkedlist
- ArrayList是实现了基于动态数组的数据结构(双向链表),LinkedList基于链表的数据结构。
- 对于随机访问get和set,ArrayList觉得优于LinkedList,因为LinkedList要移动指针。
- 对于新增和删除操作add和remove,LinedList比较占优势,因为ArrayList要移动数据。 这一点要看实际情况的。若只对单条数据插入或删除,ArrayList的速度反而优于LinkedList。但若是批量随机的插入删除数据,LinkedList的速度大大优于ArrayList, 因为ArrayList每插入一条数据,要移动插入点及之后的所有数据,而LinkedList只需要移动指针。
Vector和ArrayList
- Vector是线程同步的,所以它也是线程安全的,而Arraylist是线程异步的,是不安全的。如果不考虑到线程的安全因素,一般用arraylist效率比较高。
- 如果集合中的元素的数目大于目前集合数组的长度时,Vector增长率为目前数组长度的100%,而Arraylist增长率为目前数组长度的50%。如果在集合中使用数据量比较大的数据,用vector有一定的优势。
- 如果查找一个指定位置的数据,Vector和Arraylist使用的时间是相同的,如果频繁的访问数据,这个时候使用Vector和Arraylist都可以。
- ArrayList 和Vector是采用数组方式存储数据,此数组元素数大于实际存储的数据以便增加和插入元素,都允许直接序号索引元素,但是插入数据要涉及到数组元素移动等内存操作,所以索引数据快,插入数据慢,Vector由于使用了synchronized方法(线程安全)所以性能上比ArrayList要差。
Queue
- 队列是一种数据结构。它有两个基本操作:在队列尾部加人一个元素,和从队列头部移除一个元素就是说,队列以一种先进先出的方式管理数据,如果你试图向一个 已经满了的阻塞队列中添加一个元素或者是从一个空的阻塞队列中移除一个元索,将导致线程阻塞.在多线程进行合作时,阻塞队列是很有用的工具。工作者线程可 以定期地把中间结果存到阻塞队列中而其他工作者线线程把中间结果取出并在将来修改它们。队列会自动平衡负载。如果第一个线程集运行得比第二个慢,则第二个 线程集在等待结果时就会阻塞。如果第一个线程集运行得快,那么它将等待第二个线程集赶上来。
Set
- HashSet与TreeSet:HashSet通过hashcode对其内容进行快速查找,而TreeSet中所有的元素都保持着某种固定的顺序,如果你需要得到一个有序的结果你就应该使用TreeSet。
- HashSet : 为快速查找设计的Set。存入HashSet的对象必须定义hashCode()。
- TreeSet : 保存次序的Set,底层为树结构。使用它可以从Set中提取有序的序列。
- LinkedHashSet : 具有HashSet的查询速度,且内部使用链表维护元素的顺序(插入的次序)。于是在使用迭代器遍历Set时,结果会按元素插入的次序显示。
2、Map的实现类的描述
HashMap与TreeMap
- HashMap通过hashcode对其内容进行快速查找,而TreeMap中所有的元素都保持着某种固定的顺序,如果你需要得到一个有序的结果你就应该使用TreeMap(HashMap中元素的排列顺序是不固定的)。
- 在Map 中插入、删除和定位元素,HashMap是最好的选择。但如果您要按自然顺序或自定义顺序遍历键,那么TreeMap会更好。使用HashMap要求添加的键类明确定义了hashCode()和 equals()的实现。
- 两个map中的元素一样,但顺序不一样,导致hashCode()不一样。
- 同样做测试:在HashMap中,同样的值的map,顺序不同,equals时,false。而在TreeMap中,同样的值的map,顺序不同,equals时,true。说明,TreeMap在equals()时是整理了顺序了的。
HashTable与HashMap
- 同步性:Hashtable是线程安全的,也就是说是同步的,而HashMap是线程序不安全的,不是同步的。
- HashMap允许存在一个为null的key,多个为null的value 。
- hashtable的key和value都不允许为null。