1、本章学习目标:理解泛型的概念 掌握泛型类的创建和使用 理解泛型的有界类型和通配符的使用,了解泛型的限制 理解Java集合框架的结构、迭代器接口 掌握常用接口及实现类的使用 了解集合转换第十章第十章 泛型与集合泛型与集合第第1 1节节part泛型 从JDK 5.0开始,Java引入“参数化类型(parameterized type)”的概念,这种参数化类型称为“泛型(Generic)”。泛型是将数据类型参数化,即在编写代码时将数据类型定义成参数,这些类型参数在使用之前再进行指明。泛型提高了代码的重用性,使得程序更加灵活、安全和简洁。泛型本节概述 在JDK 5.0之前,为了实现参数类型的任意化,都
2、是通过Object类型来处理。但这种处理方式所带来的缺点是需要进行强制类型转换,此种强制类型转换不仅使代码臃肿,而且要求程序员必须对实际所使用的参数类型已知的情况下才能进行,否则容易引起ClassCastException异常。从JDK 5.0开始,Java增加对泛型的支持。使用泛型之后就不会出现上述问题。泛型的好处是在程序编译期会对类型进行检查,捕捉类型不匹配错误,以免引起ClassCastException异常;而且泛型不需要进行强制转换,数据类型都是自动转换的。泛型经常使用在类、接口和方法的定义中,分别称为泛型类、泛型接口和泛型方法。泛型类是引用类型,在内存堆中。10.1.1泛型定义泛型
3、定义定义泛型类的语法格式如下:访问符 class 类名 /类体.其中:(1)尖括号中是类型参数列表,可以由多个类型参数组成,多个类型参数之间使用“,”隔开。(2)类型参数只是占位符,一般使用大写的“T”、“U”、“V”等作为类型参数。下述代码示例了泛型类的定义,代码如下所示。class Node private T data;public Node next;/省略.10.1.1泛型定义泛型定义 从Java 7开始,实例化泛型类时只需给出一对尖括号“”即可,Java可以推断尖括号中的泛型信息。将两个尖括号放在一起像一个菱形,因此也被称为“菱形”语法。Java 7“菱形”语法实例化泛型类的格式如
4、下:类名 对象=new 类名(构造方法参数列表);例如:Node myNode=new Node();下述代码示例了一个泛型类的定义,代码如下所示。10.1.1泛型定义【代码10.1】Generic.javapackage com;public class Generic private T data;public Generic()public Generic(T data)this.data=data;public T getData()return data;public void setData(T data)this.data=data;public void showDataTyp
5、e()System.out.println(数据的类型是:+data.getClass().getName();10.1.1泛型定义 上述代码定义了一个名为Generic的泛型类,并提供两个构造方法。私有属性data的数据类型采用泛型,可以在使用时在进行指定。showDataType()方法显示data属性的具体类型名称,其中“getClass().getName()”用于获取对象的类名。下述代码示例了泛型类的实例化,并访问相应方法,代码如下所示。【代码10.2】GenericExample.javapackage com;public class GenericExample public
6、static void main(String args)Generic str=new Generic(字符串类型泛型类!);str.showDataType();System.out.println(str.getData();System.out.println(-);/定义泛型类的一个Double版本 Generic dou=new Generic(3.1415);dou.showDataType();System.out.println(dou.getData();10.1.1泛型定义 上述代码使用Generic泛型类,并分别实例化为String和Double两种不同类型的对象。程序
7、运行结果如下:数据的类型是:java.lang.String 欢迎使用泛型类!-数据的类型是:java.lang.Double 3.141510.1.2通配符通配符当使用一个泛型类时(包括声明泛型变量和创建泛型实例对象),都应该为此泛型类传入一个实参,否则编译器会提出泛型警告。假设现在定义一个方法,该方法的参数需要使用泛型,但类型参数是不确定的,此时如果考虑使用Object类型来解决,编译时则会出现错误。以之前定义的泛型类Generic为例,考虑如下代码:【代码10.3】NoWildcardExample.javapackage com;public class NoWildcardExamp
8、le public static void myMethod(Generic g)g.showDataType();public static void main(String args)/参数类型是ObjectGeneric gstr=new Generic(Object);myMethod(gstr);/参数类型是IntegerGeneric gint=new Generic(12);/这里将产生一个错误myMethod(gint);/参数类型是IntegerGeneric gdou=new Generic(12.0);/这里将产生一个错误myMethod(gdou);10.1.2通配符
9、上述代码中定义的myMethod()方法的参数是泛型类Generic,该方法的意图是能够处理各种类型参数,但在使用Generic类时必须指定具体的类型参数,此处在不使用通配符的情况下,只能使用“Generic”的方式。这种方式将造成main()方法中的语句编译时产生类型不匹配的错误,程序无法运行。程序中出现的这个问题,可以使用通配符解决。通配符是由“?”来表示一个未知类型,从而解决类型被限制、不能动态根据实例进行确定的缺点。下述代码使用通配符“?”重新实现上述处理过程,实现处理各种类型参数的情况,代码如下所示。10.1.2通配符【代码10.4】UseWildcardExample.javapa
10、ckage com;public class UseWildcardExample public static void myMethod(Generic g)g.showDataType();public static void main(String args)/参数类型是StringGeneric gstr=new Generic(Object);myMethod(gstr);/参数类型是IntegerGeneric gint=new Generic(12);myMethod(gint);/参数类型是IntegerGeneric gdou=new Generic(12.0);myMeth
11、od(gdou);10.1.2通配符 上述代码定义了myMethod()方法时,使用“Generic”通配符的方式作为类型参数,如此便能够处理各种类型参数,且程序编译无误,能够正常运行。程序运行结果如下:数据的类型是:java.lang.String 数据的类型是:java.lang.Integer 数据的类型是:java.lang.Double有界类型有界类型 泛型的类型参数可以是各种类型,但有时候需要对类型参数的取值进行一定程度的限制,以便类型参数在指定范围内。针对这种情况,Java提供了“有界类型”,来限制类型参数的取值范围。有界类型分两种:(1)使用extends关键字声明类型参数的上
12、界。(2)使用super关键字声明类型参数的下界。10.1.3有界类型有界类型1.1.上界上界 使用extends关键字可以指定类型参数的上界,限制此类型参数必须继承自指定的父类或父类本身。被指定的父类则称为类型参数的“上界(upper bound)”。类型参数的上界可以在定义泛型时进行指定,也可以在使用泛型时进行指定,其语法格式分别如下:/定义泛型时指定类型参数的上界 访问符 class 类名/类体./使用泛型时指定类型参数的上界 泛型类 例如:/定义泛型时指定类型参数的上界 public class Generic/类体./使用泛型时指定类型参数的上界 Generic 上述代码限制了泛型类
13、Generic的类型参数必须是Number类及其子类,因此可以将Number类称为此类型参数的上界。Java中Number类是一个抽象类,所有数值类都继承此抽象类,即Integer、Long、Float、Double等用于数值操作的类都继承Number类。10.1.3有界类型下述代码示例了使用类型参数的上界,代码如下所示。【代码10.5】UpBoundGenericExample.javapackage com;class UpBoundGeneric private T data;public UpBoundGeneric()public UpBoundGeneric(T data)this
14、.data=data;public T getData()return data;public void setData(T data)this.data=data;public void showDataType()System.out.println(数据的类型是:+data.getClass().getName();10.1.3有界类型public class UpBoundGenericExample/使用泛型Generic时指定其类型参数的上界public static void myMethod(Generic g)g.showDataType();public static vo
15、id main(String args)/参数类型是IntegerGeneric gint=new Generic(1);myMethod(gint);/参数类型是LongGeneric glong=new Generic(10L);myMethod(glong);/参数类型是StringGeneric gstr=new Generic(String);/产生错误/myMethod(gstr);10.1.3有界类型/使用已经限定参数的泛型UpBoundGenericUpBoundGeneric ubgint=new UpBoundGeneric(20);ubgint.showDataType(
16、);UpBoundGeneric ubglon=new UpBoundGeneric(20L);ubglon.showDataType();/产生错误/UpBoundGeneric ubgstr=new UpBoundGeneric(指定上界);10.1.3有界类型 上述代码中定义了一个泛型类UpBoundGeneric,并指定其类型参数的上界是Number类。在定义myMethod()方法时指定泛型类Generic的类型参数的上界也是Number类。在main()方法中进行使用时,当类型参数不是Number的子类时都会产生错误。因UpBoundGeneric类在定义时就已经限定了类型参数的上
17、界,所以出现“UpBoundGeneric”就会报错。Generic类在定义时并没有上界限定,而是在定义myMethod()方法使用Generic类才进行限定的,因此出现“Generic”不会报错,调用“myMethod(gstr)”时才会报错。程序运行结果如下所示:数据的类型是:java.lang.Integer 数据的类型是:java.lang.Long 数据的类型是:java.lang.Integer 数据的类型是:java.lang.Long2.2.下界下界 使用super关键字可以指定类型参数的下界,限制此类型参数必须是指定的类型本身或其父类,直至Object类。被指定的类则称为类型
18、参数的“下界(lower bound)”。类型参数的下界通常在使用泛型时进行指定,其语法格式如下所示:泛型类 例如:Generic 上述代码限制了泛型类Generic的类型参数必须是String类本身或其父类Object,因此可以将String类称为此类型参数的下界。下述代码示例泛型类型参数下界的声明和使用,代码如下所示。10.1.3有界类型【代码10.6】LowBoundGenericExample.javapackage com;public class LowBoundGenericExample/使用泛型Generic时指定其类型参数的下界public static void myMe
19、thod(Generic g)g.showDataType();public static void main(String args)/参数类型是StringGeneric gstr=new Generic(String类本身);myMethod(gstr);/参数类型是ObjectGeneric gobj=new Generic(10);myMethod(gobj);/参数类型是IntegerGeneric gint=new Generic(10);/产生错误/myMethod(gint);10.1.3有界类型 上述代码在定义myMethod()方法时指定泛型类Generic的类型参数的上
20、界是String类,因此在main()方法中进行使用时,当参数类型不是String类或其父类Object时,都会产生错误。程序运行结果如下:数据的类型是:java.lang.String 数据的类型是:java.lang.Integer 泛型中使用extends关键字限制类型参数必须是指定的类本身或其子类,而super关键字限制类型参数必须是指定的类本身或其父类。在泛型中经常使用extends关键字指定上界,而很少使用super关键字指定下界。10.1.3有界类型 Java语言没有真正实现泛型。Java程序在编译时生成的字节码中是不包含泛型信息的,泛型的类型信息将在编译处理时被擦除掉,这个过程
21、称为类型擦除。这种实现理念造成Java泛型本身有很多漏洞,虽然Java 8对类型推断进行了改进,但依然需要对泛型的使用上做一些限制,其中大多数限制都是由类型擦除和转换引起的。Java对泛型的限制如下:(1)泛型的类型参数只能是类类型(包括自定义类),不能是简单类型。(2)同一个泛型类可以有多个版本(不同参数类型),不同版本的泛型类的实例是不兼容的,例如:“Generic”与“Generic”的实例是不兼容的。(3)定义泛型时,类型参数只是占位符,不能直接实例化,例如:“new T()”是错误的。(4)不能实例化泛型数组,除非是无上界的类型通配符,例如:“Generic a=new Generi
22、c 10”是错误的,而“Generic a=new Generic 10”是被允许的。(5)泛型类不能继承Throwable及其子类,即泛型类不能是异常类,不能抛出也不能捕获泛型类的异常对象,例如:“class GenericException extends Exception”、“catch(T e)”都是错误的。10.1.4泛型的限制泛型的限制第第2 2节节part集合概述 Java的集合类是一些常用的数据结构,例如:队列、栈、链表等。Java集合就像一种“容器”,用于存储数量不等的对象,并按照规范实现一些常用的操作和算法。程序员在使用Java的集合类时,不必考虑数据结构和算法的具体实现
23、细节,根据需要直接使用这些集合类并调用相应的方法即可,从而提高了开发效率。集合概述本节概述10.2.1集合框架 在JDK 5.0之前,Java集合会丢失容器中所有对象的数据类型,将所有对象都当成Object类型进行处理。从JDK 5.0增加泛型之后,Java集合完全支持泛型,可以记住容器中对象的数据类型,从而可以编写更简洁、健壮的代码。Java所有的集合类都在java.util包下,从JDK 5.0开始为了处理多线程环境下的并发安全问题,又在java.util.concurrent包下提供了一些多线程支持的集合类。Java的集合类主要由两个接口派生而出:Collection和Map,这两个接口
24、派生出一些子接口或实现类。Collection和Map是集合框架的根接口,如图10.1所示是Collection集合体系的继承树。集合框架10.2.1集合框架Collection接口下有3个子接口:(1)Set接口:无序、不可重复的集合;(2)Queue接口:队列集合;(3)List接口:有序、可以重复的集合。10.2.1集合框架 如图10.2所示是Map集合体系的继承树。所有Map的实现类用于保存具有映射关系的数据,即Map保存的每项数据都是由key-value键值对组成。Map中的key用于标识集合中的每项数据,是不可重复的,可以通过key来获取Map集合中的数据项。10.2.1集合框架
25、Java中的集合分为三大类:(1)Set集合:将一个对象添加到Set集合时,Set集合无法记住添加的顺序,因此Set集合中的元素不能重复,否则系统无法识别该元素,访问Set集合中的元素也只能根据元素本身进行访问;(2)List集合:与数组类似,List集合可以记住每次添加元素的顺序,因此可以根据元素的索引访问List集合中的元素,List集合中的元素可以重复且长度是可变的;(3)Map集合:每个元素都是有key/value键值对组成,可以根据每个元素的key来访问对应的value,Map集合中的key不允许重复,value可以重复。本章主要介绍常用的集合接口及其实现类,例如List、Set、M
26、ap和Queue集合接口,以及对应的实现类ArrayList、HashSet、HashMap和LinkedList。10.2.2迭代器接口 迭代器(Iterator)可以采用统一的方式对Collection集合中的元素进行遍历操作,开发人员无需关心Collection集合中的内容,也不必实现IEnumerable或者IEnumerator接口就能够使用foreach循环遍历集合中的部分或全部元素。Java从JDK 5.0开始增加了Iterable新接口,该接口是Collection接口的父接口,因此所有实现了Iterable的集合类都是可迭代的,都支持foreach循环遍历。Iterable接
27、口中的iterator()方法可以获取每个集合自身的迭代器Iterator。Iterator是集合的迭代器接口,定义了常见的迭代方法,用于访问、操作集合中的元素。Iterator接口中的方法如表10-1所示:迭代器接口10.2.2迭代器接口下述代码示范了Iterator接口中的方法的应用,代码如下所示。【代码10.7】IteratorExample.javapackage com;import java.util.Collection;import java.util.HashSet;import java.util.Iterator;public class IteratorExample
28、public static void main(String args)/创建一个集合Collection city=new HashSet();city.add(重庆);city.add(成都);city.add(北京);city.add(上海);/直接显示集合元素:System.out.print(开始的城市有:+city+);System.out.println();10.2.2迭代器接口/获取city集合对应的迭代器Iterator it=city.iterator();while(it.hasNext()/it.next()方法返回的数据类型是Object类型,需要强制转换Strin
29、g c=(String)it.next();System.out.print(c+);if(c.equals(成都)it.remove();System.out.println();System.out.print(最后的城市有:+city+);程序运行结果如下:开始的城市有:上海,北京,重庆,成都 上海 北京 重庆 成都 最后的城市有:上海,北京,重庆 第第3 3节节part集合类10.3.1Collection接口 Collection接口是Set、Queue和List接口的父接口,该接口中定义的方法可以操作这三个接口中的任一个集合,Collection接口中常用的方法如表10-2所示。C
30、ollection接口10.3.1 使用Collection需要注意以下几点问题:(1)add()、addAll()、remove()、removeAll()和retainAll()方法可能会引发不支持该操作的UnsupportedOperationException异常。(2)将一个不兼容的对象添加到集合中时,将产生ClassCastException异常。(3)Collection接口没有提供获取得某个元素的方法,但可以通过iterator()方法获取迭代器来遍历集合中的所有元素.(4)虽然Collection中可以存储任何Object对象,但不建议在同一个集合容器中存储不同类型的对象,建
31、议使用泛型增强集合的安全性,以免引起ClassCastException异常。下述代码示例了如何操作Collection集合里的元素,代码如下所示。Collection接口10.3.1【代码10.8】CollectionExample.javapackage com;import java.util.ArrayList;import java.util.Collection;public class CollectionExample public static void main(String args)/创建一个Collection对象的集合,该集合用ArrayList类实例化Collec
32、tion c=new ArrayList();/添加元素c.add(Java程序设计);c.add(12);c.add(Android程序设计);System.out.println(c集合元素的个数为:+c.size();/删除指定元素c.remove(12);System.out.println(删除后,c集合元素的个数为:+c.size();/判断集合是否包含指定元素System.out.println(“集合中是否包含”Java程序设计“字符串:”+c.contains(“Java程序设计”);Collection接口10.3.1/查看c集合的所有元素System.out.printl
33、n(c集合的元素有:+c);/清空集合中的元素c.clear();/判断集合是否为空System.out.println(c集合是否为空:+c.isEmpty();程序运行结果如下:c集合元素的个数为:3删除后,c集合元素的个数为:2集合中是否包含Java程序设计字符串:truec集合的元素有:Java程序设计,Android程序设计c集合是否为空:trueCollection接口10.3.2List接口及其实现类 List是Collection接口的子接口,可以使用Collection接口中的全部方法。因为List是有序、可重复的集合,所以List接口中又增加一些根据索引操作集合元素的方法,
34、常用的方法如表10-3所示。List接口及其实现类10.3.2List接口及其实现类 List集合默认按照元素添加顺序设置元素的索引,索引从0开始,例如:第一次添加的元素索引为0,第二次添加的元素索引为1,第n次添加的元素索引为n-1。当使用无效的索引时将产生IndexOutOfBoundsException异常。ArrayList和Vector是List接口的两个典型实现类,完全支持List接口的所有功能方法。ArrayList称为“数组列表”,而Vector称为“向量”,两者都是基于数组实现的列表集合,但该数组是一个动态的、长度可变的、并允许再分配的Object数组。ArrayList和V
35、ector在用法上几乎完全相同,但由于Vector从JDK 1.0开始就有了,所以Vector中提供了一些方法名很长的方法,例如:addElement()方法,该方法跟add()方法没有任何区别。10.3.2List接口及其实现类 ArrayList和Vector虽然在用法上相似,但两者在本质上还是存在区别的:(1)ArrayList是非线程安全的,当多个线程访问同一个ArrayList集合时,如果多个线程同时修改ArrayList集合中的元素,则程序必须手动保证该集合的同步性。(2)Vector是线程安全的,程序无需手动保证该集合的同步性。正因为Vector是线程安全的,所以Vector的性
36、能要比ArrayList低。在实际应用中,即使要保证线程安全,也不推荐使用Vector,因为可以使用Collections工具类将一个ArrayList变成线程安全的。下述代码示例了ArrayList类的使用,代码如下所示。10.3.2List接口及其实现类【代码10.9】ArrayListExample.javapackage com;import java.util.ArrayList;import java.util.Iterator;public class ArrayListExample public static void main(String args)/使用泛型ArrayL
37、ist集合ArrayList array=new ArrayList();/添加元素array.add(北京);array.add(上海);array.add(广州);array.add(重庆);array.add(深圳);System.out.print(使用foreach遍历集合:);for(String s:array)System.out.print(s+);System.out.println();System.out.print(使用Iterator迭代器遍历集合:);10.3.2List接口及其实现类/获取迭代器对象Iterator it=array.iterator();whi
38、le(it.hasNext()System.out.print(it.next()+);/删除指定索引和指定名称的元素array.remove(0);array.remove(广州);System.out.println();System.out.print(删除后的元素有:);for(String s:array)System.out.print(s+);程序运行结果如下:使用foreach遍历集合:北京 上海 广州 重庆 深圳 使用Iterator迭代器遍历集合:北京 上海 广州 重庆 深圳 删除后的元素有:上海 重庆 深圳 10.3.3Set接口及其实现类 Set集合类似一个罐子,可以将
39、多个元素丢进罐子里,但不能记住元素的添加顺序,因此不允许包含相同的元素。Set接口继承Collection接口,没有提供任何额外的方法,其用法与Collection一样,只是特性不同(Set中的元素不重复)。Set接口常用的实现类包括HashSet、TreeSet和EnumSet,这三个实现类各具特色:(1)HashSet是Set接口的典型实现类,大多数使用Set集合时都使用该实现类。HashSet使用Hash算法来存储集合中的元素,具有良好的存、取以及查找性。(2)TreeSet采用Tree“树”的数据结构来存储集合元素,因此可以保证集合中的元素处于排序状态。TreeSet支持两种排序方式:
40、自然排序和定制排序,默认情况下采用自然排序。(3)EnumSet是一个专为枚举类设计的集合类,其所有元素必须是指定的枚举类型。EnumSet集合中的元素也是有序的,按照枚举值顺序进行排序Set接口及其实现类10.3.3Set接口及其实现类 HashSet及其子类都是采用Hash算法来决定集合中元素的存储位置,并通过Hash算法来控制集合的大小。Hash表中可以存储元素的位置称为“桶(bucket)”,通常情况下,单个桶只存储一个元素,此时性能最佳,Hash算法可以根据HashCode值计算出桶的位置,并从桶中取出元素。但当发生Hash冲突时,单个桶会存储多个元素,这些元素以链表的形式存储。下述
41、代码示例了HashSet实现类的具体应用,代码如下所示。10.3.3Set接口及其实现类【代码10.10】HashSetExample.javapackage com;import java.util.HashSet;import java.util.Iterator;public class HashSetExample public static void main(String args)/使用泛型HashSetHashSet hs=new HashSet();/向集合中添加元素hs.add(12);hs.add(3);hs.add(24);hs.add(24);hs.add(5);/直
42、接输出HashSet集合对象System.out.println(hs);/使用foreach循环遍历for(int a:hs)System.out.print(a+);System.out.println();hs.remove(3);/删除指定元素System.out.print(删除后剩下的数据:);/获取HashSet的迭代器Iterator iterator=hs.iterator();/使用迭代器遍历while(iterator.hasNext()System.out.print(iterator.next()+);程序运行结果如下:3,5,24,123 5 24 12 删除后剩下
43、的数据:5 24 12 通过运行结果可以发现,HashSet集合中的元素是无序的,且没有重复元素。10.3.3Set接口及其实现类下述代码示例了TreeSet实现类的使用,代码如下所示。【代码10.11】TreeSetExample.javapackage com;import java.util.Iterator;import java.util.TreeSet;public class TreeSetExample public static void main(String args)TreeSet hs=new TreeSet();hs.add(上海);hs.add(重庆);hs.ad
44、d(广州);hs.add(成都);hs.add(重庆);System.out.println(hs);for(String str:hs)System.out.print(str+);hs.remove(重庆);System.out.println();System.out.print(删除后剩下的数据:);Iterator iterator=hs.iterator();while(iterator.hasNext()System.out.print(iterator.next()+);程序运行结果如下:上海,广州,成都,重庆 上海 广州 成都 重庆 删除后剩下的数据:上海 广州 成都 通过运
45、行结果可以看出,TreeSet集合中的元素安照字符串的内容进行排序,输出的元素都是有序的,但也不能包含重复元素。10.3.4Queue接口及其实现类 Queue用于模拟队列这种数据结构,通常以“先进先出(FIFO)”的方式排序各个元素,即最先入队的元素最先出队。Queue接口继承Collection接口,除了Collection接口中的基本操作外,还提供了队列的插入、提取和检查操作,且每个操作都存在两种形式:一种操作失败时抛出异常;另一种操作失败时返回一个特殊值(null或false)。Queue接口中的常用方法如表10-4所示。Queue接口及其实现类10.3.4Queue接口及其实现类 Q
46、ueue接口有一个PriorityQueue实现类。PriorityQueue类是基于优先级的无界队列,通常称为“优先级队列”。优先级队列的元素按照其自然顺序或定制排序,优先级队列不允许使用null元素,依靠自然顺序的优先级队列不允许插入不可比较的对象。下述代码示例了PriorityQueue实现类的使用,代码如下所示。Queue接口及其实现类10.3.4Queue接口及其实现类【代码10.12】PriorityQueueExample.javapackage com;import java.util.Iterator;import java.util.PriorityQueue;public
47、 class PriorityQueueExample public static void main(String args)PriorityQueue pq=new PriorityQueue();pq.offer(6);pq.offer(-3);pq.offer(20);pq.offer(18);System.out.println(pq);/访问队列的第一个元素System.out.println(“poll:”+pq.poll();System.out.print(“foreach遍历:”);for(Integer e:pq)System.out.print(e+“”);System
48、.out.println();System.out.print(“迭代器遍历:”);Iterator iterator=pq.iterator();while(iterator.hasNext()System.out.print(iterator.next()+“”);程序运行结果如下:-3,6,20,18poll:-3foreach遍历:6 18 20 迭代器遍历:6 18 2010.3.4Queue接口及其实现类 除此之外,Queue还有一个Deque接口,Deque代表一个“双端队列”,双端队列可以同时从两端来添加、删除元素。Deque接口中定义在双端队列两端插入、移除和检查元素的方法,
49、其常用方法如表10-5所示。10.3.4Queue接口及其实现类 Java为Deque提供了ArrayDeque和LinkedList两个实现类。ArrayDeque称为“数组双端队列”,是Deque接口的实现类,其特点如下:(1)ArrayDeque没有容量限制,可以根据需要增加容量;(2)ArrayDeque不是基于线程安全的,在没有外部代码同步时,不支持多个线程的并发访问;(3)ArrayDeque禁止添加null元素;(4)ArrayDeque在用作堆栈时快于Stack,在用作队列时快于LinkedList。下述代码示例了ArrayDeque实现类的使用,代码如下所示。10.3.4Qu
50、eue接口及其实现类【代码10.13】ArrayDequeExample.javapackage com;import java.util.*;public class ArrayDequeExample public static void main(String args)/使用泛型ArrayDeque集合ArrayDeque queue=new ArrayDeque();/在队尾添加元素queue.offer(上海);/在队头添加元素queue.push(北京);/在队头添加元素queue.offerFirst(南京);/在队尾添加元素queue.offerLast(重庆);System