集合:通常情况下,把具有相同性质的一类东西,汇聚成一个整体,可以称为集合。
集合框架:为表示和操作集合而规定的一种统一的标准的体系结构。任何集合框架都包含三大块内容:对外的接口、接口的实现和对集合运算的算法。
接口:即表示集合的抽象数据类型。接口提供了让我们对集合中所表示的内容进行单独操作的可能。
实现:也就是集合框架中接口的具体实现。实际它们就是那些可复用的数据结构。
算法:在一个实现了某个集合框架中的接口的对象身上完成某种有用的计算的方法,例如查找、排序等。
集合框架提供的数据结构和算法,能让你在编程的时候花费更多的注意力在程序的重要部分上,而不用为了程序的底层设计消耗太多的精力。
Java集合框架图
Java集合框架图简化图
一、Collection
Collection接口提供了一组操作成批对象的方法。它提供了基本操作如添加、删除。它也支持查询操作如是否为空isEmpty()方法等。
Collection不提供get()方法。如果要遍历Collectin中的元素,就必须用Iterator
二、Iterator 迭代器
Collection 接口的iterator()方法返回一个 Iterator迭代器。Iterator接口方法能以迭代方式逐个访问集合中各个元素,并安全的从Collection中除去适当的元素。
boolean hasNext():判断是否存在另一个可访问的元素
Object next():返回要访问的下一个元素。如果到达集合结尾,则抛出NoSuchElementException异常。
void remove():删除上次访问返回的对象。本方法必须紧跟在一个元素的访问后执行。如果上次访问后集合已被修改,方法将抛出IllegalStateException。
迭代器是故障快速修复的。这意味着,当另一个线程修改底层集合的时候,如果正在用Iterator遍历集合,那么,Iterator就会抛出ConcurrentModificationException异常。
Collection 接口的iterator()方法返回一个 Iterator迭代器。Iterator接口方法能以迭代方式逐个访问集合中各个元素,并安全的从Collection中除去适当的元素。
boolean hasNext():判断是否存在另一个可访问的元素
Object next():返回要访问的下一个元素。如果到达集合结尾,则抛出NoSuchElementException异常。
void remove():删除上次访问返回的对象。本方法必须紧跟在一个元素的访问后执行。如果上次访问后集合已被修改,方法将抛出IllegalStateException。
迭代器是故障快速修复的。这意味着,当另一个线程修改底层集合的时候,如果正在用Iterator遍历集合,那么,Iterator就会抛出ConcurrentModificationException异常。
★Iterator对ArrayList(LinkedList)的操作限制:
刚实例化的迭代器如果还没有进行后移(next)操作是不能马上进行删除与修改操作的。
可以用ListIterator对集合连续添加与修改,但不能连续删除。
进行添加操作后是不能立即进行删除与修改操作的。
进行删除操作后可以进行添加,但不能进行修改操作。
进行修改后是可以立即进行删除与添加操作的。
刚实例化的迭代器如果还没有进行后移(next)操作是不能马上进行删除与修改操作的。
可以用ListIterator对集合连续添加与修改,但不能连续删除。
进行添加操作后是不能立即进行删除与修改操作的。
进行删除操作后可以进行添加,但不能进行修改操作。
进行修改后是可以立即进行删除与添加操作的。
三、List
List接口继承了Collection接口以定义一个允许重复项的有序集合。该接口不但能够对列表的一部分进行处理,还添加了面向位置的操作。
它的具体实现类常用的有ArrayList和LinkedList。
1. ArrayList是一种数组的形式进行存储,ArrayList能灵活的设置数组的大小(但是,数组扩容时的消耗比较大)。因此ArrayList的特点是读取速度快(直接通过数组下标访问),增删元素的速度慢(每次增删都要移动指定位置之后的全部元素),适合对数据的随机访问多的程序。
2. LinkedList是链表的结构,LinkedList增删元素的速度很快(直接增加节点,并修改地址就可以完成元素的增删),读取的速度慢(读取元素需要从头结点或者尾节点开始一个个的遍历链表),适合读写操作多的程序。
3. Vector的功能与ArrayList几乎相同,但是是基于线程同步的,它除了包含访问和修改向量的同步方法之外,跟ArrayList一样,也是以数组实现添加、删除、读取。
4. Stack继承自Vector类,但一般只作为栈的功能来使用。
★将ArrayList作为默认首选,只有当程序的性能因为经常从list中间进行插入和删除而变差的时候,才去选择LinkedList。Vector通常不如ArrayList快,则且应该避免使用。
四、Set
Set维持它自己的内部排序,随机访问不具有意义。另外元素不可重复。
1. HashSet的查询速度最快,因为内部以HashMap来实现,所以插入元素不能保持插入时的顺序。
2. TreeSet是基于TreeMap的,内部以TreeMap来实现。TreeSet是一个总是处于排序状态的set,它实现了SortedSet接口。
3. LinkedHashSet继承了HashSet,但是能保持元素的插入次序(因为内部使用LinkedHashMap实现,所以能保持元素插入次序)。
五、Map
Map提供了一个更通用的元素存储方法,它是一种把键对象和值对象进行关联的容器。散列图HashMap,链式散列图LinkedHashMap,树形图TreeMap是Map的3种实现。
1. HashMap是基于哈希表的Map接口的实现,增删查改时,Map通过key值计算哈希函数确定元素的位置。它是为快速查询而设计的,其内部定义了一个hash表数组(Entry[] table),元素会通过哈希转换函数将元素的哈希地址转换成数组中存放的索引,如果有冲突,则使用散列链表的形式将所有相同哈希地址的元素串起来,可能通过查看HashMap.Entry的源码它是一个单链表结构。
2. TreeMap键以某种排序规则排序,内部以red-black(红-黑)树数据结构实现,因而它不如HashMap那么快。
3. LinkedHashMap继承自HashMap,内部实体LinkedHashMap.Entry继承自HashMap.Entry,LinkedHashMap.Entry在HashMap.Entry的基础上新增了两个实体引用(Entry before, after),这样实体可以相互串链起来形成链,并且在LinkedHashMap中就定义了一个头节点(Entry header)用来指向循环双向链的第一个元素(通过after指向)与最后一个元素(通过before指向)。在添加一个元素时,先会通过父类HashMap将元素加入到hash表数组里,然后再会在链尾(header.before指向位置)添加(这一过程只是调整LinkedHashMap.Entry对象内部的before, after,不是创建一个新的链表结构,向里面添加元素)。其实在链中添加与删除操作与LinkedList是一样的。
★Hashtable和HashMap的区别
1. Hashtable也是以哈希表数据结构实现的,解决冲突时与HashMap也一样也是采用了散列链表的形式。Hashtable和HashMap的效率大致相同(通常HashMap更快一点)。
2. Hashtable中的方法是同步的,而HashMap中的方法在缺省情况下是非同步的。在多线程应用程序中,我们应该使用Hashtable;而对于HashMap,则需要额外的同步机制。
3. 在HashMap中,可以允许null作为键,且只可以有一个,否则覆盖,但可以有一个或多个值为null。因为当get()方法返回null值时,即可以表示HashMap中没有该键,也可以表示该键所对应的值为null,所以HashMap不能由get()方法来判断否存在某个键,而应该用containsKey()方法来判断;而Hashtable不允许null键与null值。
3. 在HashMap中,可以允许null作为键,且只可以有一个,否则覆盖,但可以有一个或多个值为null。因为当get()方法返回null值时,即可以表示HashMap中没有该键,也可以表示该键所对应的值为null,所以HashMap不能由get()方法来判断否存在某个键,而应该用containsKey()方法来判断;而Hashtable不允许null键与null值。
★TreeMap通常比HashMap慢,因为要维护排序。HashMap正是为快速查询而设计的。LinkedHashMap比HashMap慢一点,因为它维护散列数据结构的同时还要维护链表。