`
shangjava
  • 浏览: 1188954 次
  • 性别: Icon_minigender_1
  • 来自: 北京
文章分类
社区版块
存档分类
最新评论

8.Java中的集合、枚举、泛型【上】

阅读更多

(本章主要讲解Java里面会遇到的所有集合类以及相关用法,还有JDK1.5里面出来的一些关于集合和算法的新内容,主要是方便我们在开发过程中适当地注意选择,而且本章的内容相对前边章节比较少,但是代码量比较大,但是大部分内容都是个人的一些总结。当然这一个章节会涉及到JDK本身提供的一些数据结构的相关内容,以及最基本几个数据结构的相关性能分析。本来是打算先写Java的IO相关的内容,刚好最近有个项目需要经常性使用到Java里面的东西,所以先提供这一个章节给大家。很多人来Email说Java的基础数据类型一个章节的内容太少了,这点我必须说一句抱歉,因为基础数据类型是我第一次写,后来才想到使用后边这样的方式来写BLOG的内容,基础章节的东西我后边会提供专程的章节来讲解控制流程、以及各种关键字的清单。该系列教程的主要目的是为了整理一份个人使用的开发文档,如果有人转载,请来Email告知,谢谢!在整个过程里面如果发现有笔误的地方希望来Email提点:silentbalanceyh@126.com)

本章目录
1.基本概念
2.常用集合——列表、队列、栈
3.常用集合——Set集合、哈希表
4.泛型、枚举

1.基本概念
  一般情况下,在系统开发的时候经常会遇到针对大量的数据进行处理,在处理同类型数据的某些集合的时候,就会使用到一定的集合类的数据结构。在Java语言里面,集合类一般都位于java.util包里面,该包里面的集合类基本提供了我们再开发过程中常用的数据结构,直接使用起来基本可以满足我们的开发要求。JDK在设计的时候针对常用的数据结构和算法做了一些规范(接口)和实现(实现接口的类),所有抽象出来的数据结构和算法统称为Java集合框架(Java Collection Framework),所以我们在使用的时候就不需要考虑数据结构和算法实现细节,只需要使用这些类创建相关的对象出来,然后直接应用就可以了。
  i.集合的数学背景:
  常见的用法里面,集合(Collection)和数学直观的集(Set)是一个概念。集是一个唯一项组,也就是说组中没有重复项,一般情况下,在我们书写数学集合的时候不会遇到重复项;但是在Java集合框架里面,进行了更加严格的定义,针对这种概念的集合,使用Set接口以及许多实现了该接口的Set类来进行。我们在很早的数学课的时候就学过“交集”和“并集”的概念:
  根据上图可以理清楚对应的集合之间的关系,提供一些简单的集合的实例:
  • Java语言的关键字:{"import","final","static","public",...}
  • 数据库返回结果的记录集
  • 非负整数:{0,1,2,...}
  • 空集:{}【该符号为非数学符号】

  在数学定义里面,集的基本特性如下:

  • 集内只包含每项的一个实例
  • 集可以是有限的,也可以是无限的
  • 集可以定义抽象概念
  数学里面映射是一种特殊的集,一般情况称为对集,每个对表示一个元素到另一个元素的映射,在计算机领域里面,映射的例子有:
  • IP地址到域名(DNS)的映射
  • 关键在到数据库记录的映射
  • 2进制到10进制的转换的映射
  在Java集合框架里面,有严格的SetListCollectionMap的正规定义。
  ii.基本结构:
  Java集合框架(Java Collection Framework)简称JCF,下边均用JCF指代,根据整个Java语言里面的集合结构,先看一张网上摘录的图,里面提供了JCF的整体快照:
  上图来自:http://www.blogjava.net/EvanLiu/archive/2007/11/12/159884.html
  在Java里面,JCF定义了几种标准的集合接口:Collection接口、List接口、Set接口、Map接口,将上边的快照简化就变化称了下边这种简化结构:
  
  需要针对上边的图做理解的是:
  • Collection接口是一组允许重复的对象
  • Set接口继承Collection对象,但是不允许重复,而且无序
  • List接口继承Collection对象,但是允许重复,且有序
  • Map接口既不继承Set也不继承Collection
  关于它们的特性可以用一个思维导图来归纳

  iii.Collection接口、List接口、Set接口、Map接口【顶层接口】
  1)Collection接口概述:
  JCF中的根接口,Collection表示一组对象,这些对象也称为Collection的元素,有些Collection允许有重复元素,有些Collection不允许有重复元素,有些Collection是有序的,有些Collection是无序的。Java里面没有该接口的直接实现,也就是说没有任何一个具体累实现了该接口。开发过程可以自己去开发实现该接口的类,所有实现该接口的类应该提供两个标准的构造方法:[1]一个是无参数的构造方法,用于创建空集合;[2]一个则是带有Collection类型的单参数构造方法,用于创建某个与其元素相同的Collection,实际上后者可以理解为一个集合的复制过程,通过该种构造方法生成某个集合的等效的Collection。但是这种实现方式没有任何Java规范的硬性要求,仅仅是一个约定俗成。
  该接口中包含了一定的“破坏性”方法,是指可修改其操作的Collection的相关方法,如果Collection不支持该操作,则指定这些方法抛出一个UnsupportOperationException,若是这样的情况在调用Collection无效的时候,这些破坏性方法有可能会抛出该异常,这种操作没有绝对抛出异常的说法。一些Collection的实现对它们可能包含的元素有所限制,比如禁止null元素,或者说有些实现类针对某些集合的添加元素有类型限制,一旦操作失败有可能会抛出NullPointerException异常以及ClassCastException,但是有时候操作起来并不抛出异常,也仅仅是返回一个false。
  Collection的接口的定义:
publicinterfaceCollection<E>extendsIterable<E>【E代表Collection内的元素类型】
  根据该集合的定义可以知道,Java里面的Collection接口从JDK 1.5开始过后就使用了带泛型的定义:Collection<E>,而且它有一个父接口:Iterable<E>,这里简单介绍一下Iterable<E>接口:
该接口允许对象使用“foreach”语句,这种语句在java里面使用下边格式进行:
for(Stringitem : list){}
  Iterable<E>接口仅仅提供一个方法iterator(),该方法返回一个迭代器,【Iterable<E>接口是在1.5的版本中引入的】
public interfaceIterable<T>
  Collection的方法定义列表:
booleanadd(Ee)throwsUnsupportedOperationException,ClassCastException,NullPointerException,IllegalArgumentException,IllegalStateException
——确保该Collection包含该指定元素、若该调用使得Collection发生了更改返回为true,没有修改成功返回为false
booleanaddAll(Collection<?extendsE> c)throwsUnsupportedOperationException,ClassCastException,NullPointerException,IllegalArgumentException,IllegalStateException
——将指定Collection中的所有元素都添加到该Collection中
voidclear()throwsUnsupportedOperationException
——清除该Collection中的所有元素
booleancontains(Object o)throwsClassCastException,NullPointerException
——如果该Collection里面包含了指定的元素,则返回true
booleancontainsAll(Collection<?>c)throwsClassCastException,NullPointerException
——如果该Collection里面包含了指定Collection中的元素,则返回为true
booleanequals(Object o)
——比较此Collection是否与指定的对象相等
inthashCode()
——返回此Collection的hashCode值
booleanisEmpty()
——如果此Collection不包含任何元素,该方法返回为true
Iterator<E>iterator()
——返回该Collection上的一个迭代器
booleanremove(Object o)throwsClassCastException,NullPointerException,UnsupportedOperationException
——从该Collection中移除指定的单个实例,如果存在的话
booleanremoveAll(Collection<?>c)throwsClassCastException,NullPointerException,UnsupportedOperationException
——移除此Collection中那些也包含在指定Collection中的所有元素
booleanretainAll(Collection<?>c)throwsClassCastException,NullPointerException,UnsupportedOperationException
——仅保留此Collection中那些也包含在指定元素里的元素,类似一个元素合并操作
intsize()
——返回包含在Collection中的元素个数
Object[] toArray()
——返回包含此Collection中所有元素的数组
<T> T[] toArray(T[] a)throwsArrayStoreException,NullPointerException
——返回包含此Collection中所有元素的数组;返回数组的运行时类型与指定数组的运行时类型相同

  2)List接口概述:
  List接口称为有序的Collection(也可以称为序列),调用该接口可以针对列表中的元素插入的位置进行精确的控制,调用者也可以使用整数索引来访问对应的元素,并且进行搜索相关操作,该列表允许重复的元素。该接口在父接口Collection的方法iterator、add、remove、equals和hashCode方法的协定上加了一部分约定,超过了Collection本身的方法约定。List接口的元素访问比起Collection可能复杂很多:
  • 该接口提供了4种对列表元素进行定位访问的方法
  • 该接口提供了特殊的迭代器ListIterator,除了允许正常访问以外,还允许元素的插入和替换,以及双向访问【不仅仅提供next操作】
  • 该接口提供了两种方法搜索指定对象
  • 该接口提供了两种在列表的任意位置高效插入或者移除多个元素方法
  【*:在这个列表上,equals和hashCode的实现不是定义良好的】
  List接口的定义:
public interfaceList<E>extendsCollection<E>【E代表List内的元素的类型】
  List的方法定义列表【这里不重复父类Collection的方法定义】:
voidadd(intindex,Eelement)throwsUnsupportedOperationException,ClassCastException,NullPointerException,IllegalArgumentException,IndexOutOfBoundsException
——在列表的指定位置插入指定元素
booleanaddAll(intindex,Collection<?extendsE> c)throwsUnsupportedOperationException,ClassCastException,NullPointerException,IllegalArgumentException,IndexOutOfBoundsException
——将Collection里面所有的元素都插入到列表里面指定的位置,而插入进去的元素顺序按照迭代器从Collection里面迭代出来的顺序插入
Eget(intindex)throwsIndexOutOfBoundsException
——返回列表中指定索引位置的元素
intindexOf(Object o)throwsClassCastException,NullPointerException
——返回该列表中第一次出现该元素的索引,如果列表不包含此元素,就返回-1
intlastIndexOf(Object o)throwsClassCastException,NullPointerException
——返回此列表中最后出现指定元素的索引,如果该列表不包含此元素,就返回-1
ListIterator<E>listIterator()
——返回此列表元素的列表迭代器(按照适当的顺序)
ListIterator<E>listIterator(intindex)throwsIndexOutOfBoundsException
——返回列表中元素的列表迭代器(按照适当的顺序),从列表指定的位置开始
Eset(intindex,Eelement)throwsUnsupportedOperationException,ClassCastException,NullPointerException,IllegalArgumentException,IndexOutOfBoundsException
——用指定元素替换掉该索引位置本来的元素
List<E>subList(intfromIndex,inttoIndex)throwsIndexOutOfBoundsException
——返回列表中指定的fromIndex(包括)和toIndex(不包括)之间部分的一个子列表
  【*:需要注意的是,因为List接口是有序的接口,它继承的父接口Collection里面的所有操作都是针对有序和无序两种,Collection本身没有头部和尾部的概念,而List本身是存在头部和尾部的概念的,比如调用add方法,针对Collection而言仅仅是把元素添加进入该集合,但是针对List而言,默认情况是将元素添加到该List的尾部,也就是说List有一个很大的特点就是它是有序的,而且以List结构存储的元素结构在List中存在一个“位置”的概念】

  3)Set接口概述:
  一个不包含重复的无序的Collection,Set不包含两个相同的元素(使用equals方法比较返回为true),并且最多包含一个null元素,该结构是按照集合的数学定义来实现的,而且Set的特殊情况在于该集合不允许包含其自身作为元素。
  【*:如果将可变对象作为Set集合的元素,那么必须极其小心,如果对象是Set中的某个元素,以一种影响equals比较的方式改变了对象的值的话,那么这种情况下Set集合的值会变得不确定。】
  Set接口的定义:
public interfaceSet<E>extendsCollection<E>【E代表Set集合内的元素的类型】
  Set的方法列表和Collection是完全一样的,所以这里没有列出来,需要注意的是:在父接口所有的构造方法、add、equals以及hashCode等方法的协定上,Set接口还加入了其他规定,这些规定超出了从Collection接口继承的相关内容。Set集合的主要特点就是无序、不可重复,其实Set可能更容易理解,因为Set和集合的数学定义是一致的。

  4)Map接口概述:
  Map接口一般我们称为映射,它有一个很特殊的特征:一个映射不能包含重复的键,而且每个键只能映射到一个值,该接口定义如下:
public interfaceMap<K,V>【K代表此映射所维护的键的类型,V代表此映射对应的值的类型】
  Map接口提供了三种可以访问的试图集合:键集、值集、键-值关系实体集的形式查看某个映射的内容。该集合的顺序就为迭代器在该集合上迭代出来的元素的顺序,而且有些实现了该接口的类是可以保证顺序的,就是Map接口下边的实现有些是有序的,有些是无序的。
  【*:如果一个对象可变的话,它作为该Map的键的时候需要小心,这个后边深入的时候讲】
  Map接口的方法定义列表:
voidclear()throwsUnsupportedOperationException
——从此映射中移除所有的映射关系
booleancontainsKey(Object key)throwsClassCastException,NullPointerException
——如果此映射包含指定键的映射关系返回true
booleancontainsValue(Object value)throwsClassCastException,NullPointerException
——如果此映射将一个或者多个键映射到指定的值,则返回true
Set<Map.Entry<K,V>> entrySet()
——返回该映射中包含的映射关系实体集的一个视图[Map.Entry<K,V>为Map接口内的嵌套类]【键-值关系实体集视图】
booleanequals(Object o)
——比较指定的对象与此映射是否相等
Vget(Object key)throwsClassCastException,NullPointerException
——返回指定键对应的值;如果此映射不包含该映射关系,直接返回null
inthashCode()
——返回此映射的哈希吗值
booleanisEmpty()
——如果此映射中未包含键值关系映射,则返回true
Set<K>keySet()
——返回此映射中包含键的Set视图【键集视图】
Vput(Kkey,Vvalue)throwsUnsupportedOperationException,ClassCastException,NullPointerException,IllegalArgumentException
——将指定的值与此映射中的指定键关联
voidputAll(Map<?extendsK,?extendsV> m)throwsUnsupportedOperationException,ClassCastException,NullPointerException,IllegalArgumentException
——从指定映射中将所有映射关系复制到该映射里面
Vremove(Object key)throwsUnsupportedOperationException,ClassCastException,NullPointerException
——如果存在一个键的映射关系,则将其从此映射中移除
intsize()
——返回此映射中的键值映射关系数
Collection<V>values()
——返回该映射中的值的Collection视图【值集视图】
  Map接口中的嵌套接口Map.Entry<K,V>
  Map.Entry接口的定义:
public static interfaceMap.Entry<K,V>
  Map.Entry方法定义列表:
booleanequals(Object o)
——比较指定对象与该项的相等性
KgetKey()throwsIllegalStateException
——返回与此项对应的键
VgetValue()throwsIllegalStateException
——返回与此项对应的值
inthashCode()
——返回此映射项的哈希吗值
VsetValue(Vvalue)throwsUnsupportedOperationException,ClassCastException,NullPointerException,IllegalArgumentException,IllegalStateException
——用指定的值替换与此项对应的值

  iv其他java.util包里面的接口【*:该部分内容可能相对复杂,初学者暂时可以略过】
  1)Queue<E>接口(1.5):父接口[Collection<E>]
public interfaceQueue<E>extendsCollection<E>
  该接口针对Collection接口做了一定的改动,是一种带特殊数据结构的接口,它不仅仅提供了Collection的普通操作方法,而且针对每种方法都提供了不同的形式:
  [1]操作失败的时候,抛出异常;
  [2]操作失败的时候,返回一个特殊值(比如null或者false)

抛出异常 返回特殊值
插入 add(e) offer(e)
移除 remove() poll()
检查 element() peek()
  一般情况下,队列都是以FIFO(先进先出)的方式排列元素,不过有两种数据接口是例外的:优先级队列、LIFO队列(堆栈)。前者会根据比较器或元素的自然顺序进行排序,后者按照LIFO(后进先出)的方式对元素进行排序。不论使用哪种排序方式,队列的头都是调用remove()或poll()两种方法来进行元素的移除。在FIFO队列中,所有的元素都会插入到队列的队尾,其他种类的队列可能使用不同的元素放置规则,每个Queue实现必须指定该顺序属性。虽然提供了两种不同的插入、移除、检查方法,但是这些方法有一定的异同点:
  • offer方法可以插入一个元素,否则就返回false,该方法有别于Collection.add方法的地方为:add方法只能通过抛出未经检查的异常使添加元素失败,offer方法设计用于正常的失败情况,不会抛出异常
  • remove()和poll()方法主要做两个事情:[1]移除队列里面选择的元素;[2]返回该队列的头;至于该元素的顺序是根据不同的实现策略进行操作的,这两个方法唯一的不同点:当一个队列为空的时候,remove()方法抛出一个异常,而poll直接返回null。【*:这里的队列为空指代的是该队列里面不包含此元素,并不是说队列本身的引用为空,这一点小心】
  • element()和peek():直接返回队列的头元素,但是不移除
  【*:Queue实现通常不允许插入null元素,尽管某些实现没有禁止插入null。这里需要考虑到的一个问题在于,如果队列里面插入了null元素,那么在返回的时候和上边第二条可能会存在二义性,因为null的返回值在作用于poll方法的时候也代表该队列里面什么元素都不包含,如果本身存在一个null元素,在调用该方法的时候到底是某个元素为null还是这个集合里面已经什么元素都不包括在这里是无法判断的,所以一般情况下不允许将null插入到Queue的实现里面,即使有些类可以插入null元素。】

  2)Deque<E>接口(1.6):父接口[Queue<E>]
public interfaceDeque<E>extendsQueue<E>
  一个线性的Collection,支持在两端进行插入和移除操作,又称为双端队列[double ended queue的缩写],大所属Deque实现对于它们能够包含的元素没有特殊的限制,但是该接口既支持持有容量限制的双端队列,也支持没有固定大小的双端队列。该接口定义在双端队列两端访问的方法包括:插入、移除、检查,和Queue一样,提供了两种不同的形式:

第一个元素(头部) 最后一个元素(尾部)

抛出异常 特殊值 抛出异常 特殊值
插入 addFirst(e) offerFirst(e) addLast(e) offerLast(e)
移除 removeFirst() pollFirst() f
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics