Java Collections Framework

集合 OR 容器

通常我们会用数组去保存一些基本数据类型,数组是编译器支持的类型,但是数组的一个明显缺点就是具有固定尺寸,而在一般情况下,只有在程序运行的时候,我们才能知道要保存的具体数目。Java类库提供了一套相当完善的容器框架(Collections Framework)来解决这个问题。其中基本的类型是List、Set、Queue和Map。这些对象类型也被称为集合类,但是由于Java中使用了Collection这个名称指代该类库的一个子集,所以一般使用更广泛的术语“容器”来称呼它们。

容器的基本任务是保存对象,更准确地说是保存对象的引用。但是各种容器的实现是存在很大差异的,没有一种容器是绝对优秀地能够适应所有的应用场景,所以我们需要了解各种容器的底层实现,然后根据实际的情况选择合适的容器。

从下面的这张容器的分类图中就能看到Collections Framework的庞大,而且这还不包括Queue接口的实现(PriorityQueue以及各种风格的BlockingQueue等)、ConcurrentMap接口实现、CopyOnWriteArrayList和CopyOnWriteArraySet、EnumSet和EnumMap、以及Collections工具类中的多个工具方法。

Collections

Java集合框架的基本接口/类层次结构:

java.util.Collection [I] 
+--java.util.List [I] 
   +--java.util.ArrayList [C] 
   +--java.util.LinkedList [C] 
   +--java.util.Vector [C] 
      +--java.util.Stack 
+--java.util.Set [I] 
   +--java.util.HashSet [C] 
   +--java.util.SortedSet [I] 
      +--java.util.TreeSet [C] 
java.util.Map 
+--java.util.SortedMap [I] 
   +--java.util.TreeMap [C] 
+--java.util.Hashtable [C] 
+--java.util.HashMap [C] 
+--java.util.LinkedHashMap [C] 
+--java.util.WeakHashMap [C] 

[I]:接口 
[C]:类 

Java2容器类类库的用途是“保存对象”,它分为两类:

  Collection一组独立的元素,通常这些元素都服从某种规则。List必须保持元素特定的顺序,而Set不能有重复元素。

  Map一组成对的“键值对”对象,即其元素是成对的对象,最典型的应用就是数据字典,并且还有其它广泛的应用。另外,Map可以返回其所有键组成的Set和其所有值组成的Collection,或其键值对组成的Set,并且还可以像数组一样扩展多维Map,只要让Map中键值对的每个“值”是一个Map即可。

Collection是集合接口
Set子接口:无序,不允许重复。
List子接口:有序,可以有重复元素。
区别:Collections是集合类

同时,List还提供一个listIterator()方法,返回一个ListIterator接口对象,和Iterator接口相比,ListIterator添加了元素的添加,删除和设定等方法,还能向前或向后遍历。

Set和List具体子类:
Set
|————HashSet:以哈希表的形式存放元素,插入删除速度很快。

List
|————ArrayList:动态数组。
|————LinkedList:链表、队列、堆栈。

Vector是一种老的动态数组,是线程同步的,效率很低,一般不赞成使用。


Interface接口规范

Collections Framework定义了一些接口规范,那些常用的容器都会继承某些接口规范,每一种接口都对应给出相应的抽象类,如果类库提供的容器不能很好地完成你指定的任务,你可以扩写这些抽象类的子类,定制自己的容器。

Collection接口

仅仅表示一组对象的集合,而没有指定对象的存放次序,以及能否包含重复元素,Collection接口自身还继承了Iterator接口。 下面要说的很多容器都实现了Collection接口,包括List、Set、Queue、Deque等接口。需要注意的是,同为容器的Map没有实现Collection接口。 Collection接口定义了容器最基本的一些特性,包含以下的接口方法定义:

size方法:返回容器中元素的个数
contains方法:返回容器中是否包含某个元素
iterator方法:返回容器的迭代器
add方法:用于向容器中添加元素
remove方法:用于删除容器中的元素
clear方法:清空容器中的元素
toArray方法:将容器类转成相应的对象数组

List接口

List继承于Collection接口,表示一个有序容器,容器内的元素会按照加入的顺序有序地存放,允许出现重复的元素,可以基于元素位置的访问。List接口在Collection接口的基础上加上了以下方法的定义:

get方法:获取指定位置的元素
set方法:将指定位置设置成指定的元素
indexOf方法:获取指定元素在容器中的位置
listIterator方法:返回ListIterator类型的迭代器
subList方法:根据区间位置,获取容器的子容器
List接口的常见实现类有ArrayList、LinkedList、Vector等。

Set接口

继承于Collection接口,特点是不能存放相同的元素,对有序性没有要求,Set接口中的方法定义基本和Collection接口一致,没有加入新的方法定义。
常见的Set接口的实现有HashSet、SortedSet接口

Queue接口

继承于Collection接口,是一个被定义用来存放一系列等待进行某个过程元素的容器,除了一些基本的容器操作,Queue队列还提供了一些额外的插入、提取和检查的操作。
Queue接口中定义以下的方法:

add方法:将指定的元素插入此队列(如果立即可行且不会违反容量限制),在成功时返回 true,如果当前没有可用的空间,则抛出 IllegalStateException。
offer方法:将指定的元素插入此队列(如果立即可行且不会违反容量限制),当使用有容量限制的队列时,此方法通常要优于 add(E),后者可能无法插入元素,而只是抛出一个异常。
peek方法:获取但不移除此队列的头;如果此队列为空,则返回 null。
pool方法:获取并移除此队列的头;如果此队列为空,则返回 null。
remove方法:获取并移除此队列的头。
包括Deque、BlockingQueue接口都直接继承于Queue接口

Map接口

是一个关于key(键)和value(值)的映射集合,每一个key对应一个value。
Map接口中定义的一些基本方法:

size方法:返回容器中元素的个数
put方法:向容器中加入元素
remove方法:删除容器中元素
isEmpty方法:判断容器是否为空
contains方法:判断容器是否包含指定元素
clear方法:清除容器中的元素
keySet方法:返回Map的key集合,是Set类型的
实现了Map接口的一些类:HashMap、Hashtable、WeakHashMap、SynchronizedMap、ConcurrentMap接口等

Deque接口

继承于Queue接口,在JDK1.6中被加入,也叫做双端队列,即可以在队列的两端进行插入和提取操作。Deque接口在Queue接口的基础上,加上了addFirst、addLast、offerFirst、offerLast等方法,分别表示这些操作可以在两端进行。
常见的Deque的实现类:ArrayDeque、ConcurrentLinkedDeque、LinkedList、BlockingDeque等。

Collections Framework中还包含一些其他的接口,但基本由上述接口扩展而来,如SortedSet、SortedMap、BlockingQueue、BlockingDeque、ConcurrentMap等。


通用的一些实现类

类库提供了一些非常有用的基于上述接口的容器实现类,并且能够很好地胜任日常开发中的大部分场景。

HashSet

为快速查找而设计的Set,存入HashSet的对象必须定义hashCode()。基于Set接口的Hash表的实现,比较全面地实现了Set接口。元素在容器中的顺序是无序的,底层是基于HashMap的实现,key表示set容器中的值,value都是一个相同的对象,HashMap的put方法。

TreeSet

保持次序的Set,底层为树结构。使用它可以从Set中提取有序的序列。基于红黑树实现,继承于NavigableSet接口,NavigableSet也就是SortedSet的扩展,具有了为给定搜索目标报告最接近匹配项的导航方法。

LinkedHashSet

具有HashSet的查询速度,且内部使用链表维护元素的顺序(插入的次序)。于是在使用迭代器遍历Set时,结果会按元素插入的次序显示。

ArrayList

实现了List接口,底层基于数组实现,对元素的随机访问速度较快,但是插入和删除操作速度较慢。ListIterator只应该用来由后或向前遍历ArrayList,而不是用来插入和删除元素,因为这比LinkedList开销要大很多。

LinkedList

实现了List接口和Deque接口,底层是双重链表实现。当通过队列使用时,LinkedList表现为一个FIFO队列。对顺序访问进行了优化,向LinkedList中间插入与删除的开销不大,随机访问则相对较慢(可用ArrayList代替)。它具有方法addFirst()、addLast()、getFirst()、getLast()、removeFirst()、removeLast(),这些方法(没有在任何接口或基类中定义过)使得LinkedList可以当作堆栈、队列和双向队列使用。

ArrayDeque

实现了Deque,是Deque接口一个非常高效的基于数组的实现。

PriorityQueue

是一个基于优先级堆的无界优先级队列。

HashMap

基于哈希表的 Map 接口的实现。此实现提供所有可选的映射操作,并允许使用 null 值和 null 键。(除了不同步和允许使用 null 之外,HashMap 类与 Hashtable 大致相同。)此类不保证映射的顺序,特别是它不保证该顺序恒久不变。

TreeMap

它实现SortedMap 接口的基于红黑树的实现。此类保证了映射按照升序顺序排列关键字,根据使用的构造方法不同,可能会按照键的类的自然顺序进行排序(Comparable),或者按照创建时所提供的比较器(Comparator)进行排序。

LinkedHashMap

Map接口的哈希表和链表实现,具有可预期的迭代顺序。


包装实现类

在java.util.Collections工具类中提供了一系列的静态内部类容器,这些内部类也实现了Collection接口,并且具有各自的特性,可以分为以下三类:

Collections.unmodifiableInterface:返回指定Interface类型的容器,但是不允许用户去修改它们。相当于原来容器的一个不能修改的视图。

Collections.synchronizedInterface:返回指定interface类型的容器,但是是线程安全的。

Collections.checkedInterface:返回指定interface的一个动态类型安全视图。试图插入一个错误类型的元素将导致立即抛出ClassCastException。


基于特定目的的实现

WeakHashMap

我们说容器是用来保存对象的,更准确地说是用来保存对象的引用,如果一个长生命周期的容器,保持着一个无用对象的引用,就会造成GC无法回收。weakHashMap以弱键实现的基于哈希表的Map。在 WeakHashMap 中,当某个键不再正常使用时,将自动移除其条目。更精确地说,对于一个给定的键,其映射的存在并不阻止垃圾回收器对该键的丢弃,这就使该键成为可终止的,被终止,然后被回收。丢弃某个键时,其条目从映射中有效地移除,因此,该类的行为与其他的Map实现有所不同。

IdentityHashMap

此类利用哈希表实现Map接口,比较键(和值)时使用引用相等性代替对象相等性。换句话说,在 IdentityHashMap 中,当且仅当 (k1==k2) 时,才认为两个键 k1 和 k2 相等。

CopyOnWriteArrayList

ArrayList的一个线程安全的变体,其中所有可变操作(add、set 等等)都是通过对底层数组进行一次新的复制来实现的,一般需要很大的开销。

CopyOnWriteArraySet

内部使用CopyOnWriteArrayList的Set。

EnumSet

与枚举类型一起使用的专用的Set实现。枚举 set 中所有键都必须来自单个枚举类型,该枚举类型在创建 set 时显式或隐式地指定。

EnumMap

与枚举类型一起使用的专用的Map实现。枚举映射中所有键都必须来自单个枚举类型,该枚举类型在创建映射时显式或隐式地指定。枚举映射在内部表示为数组。此表示形式非常紧凑且高效。


线程安全类

下面是线程安全的同步的类:

Vector:就比ArrayList多了个同步化机制(线程安全)。

Statck:堆栈类,先进后出。

Hashtable:就比HashMap多了个线程安全。

Enumeration:枚举,相当于迭代器。

除了这些之外,其他的都是非线程安全的类和接口。

线程安全的类其方法是同步的,每次只能一个访问。是重量级对象,效率较低。对于非线程安全的类和接口,在多线程中需要程序员自己处理线程安全问题。


用于并发用的实现类

ConcurrentLinkedQueue

一个基于链接节点的无界的线程安全的队列,按照FIFO原则对元素进行排序。

ConcurrentHashMap

支持获取的完全并发和更新的所期望可调整并发的哈希表,是基于非阻塞实现的。

LinkedBlockingQueue

一个基于已链接节点的、范围任意的blocking queue,也是按照FIFO排序元素。

PriorityBlockingQueue

一个带有优先级的阻塞队列的实现。

其他的并发容器可以在java.util.concurrent包下面找到。


迭代器

迭代器是一种设计模式,它是一个对象,它可以遍历并选择序列中的对象,而开发人员不需要了解该序列的底层结构。迭代器通常被称为“轻量级”对象,因为创建它的代价小。

  Java中的Iterator功能比较简单,并且只能单向移动:

  (1) 使用方法iterator()要求容器返回一个Iterator。第一次调用Iterator的next()方法时,它返回序列的第一个元素。

  (2) 使用next()获得序列中的下一个元素。

  (3) 使用hasNext()检查序列中是否还有元素。

  (4) 使用remove()将迭代器新返回的元素删除。

  Iterator是Java迭代器最简单的实现,为List设计的ListIterator具有更多的功能,它可以向前或向后遍历List,也可以从List中插入、删除和设定元素。


参考:
http://www.2cto.com/kf/201408/330018.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值