对Java中泛型的研究与探讨

来源 :电脑知识与技术 | 被引量 : 0次 | 上传用户:wzhjxl3
下载到本地 , 更方便阅读
声明 : 本文档内容版权归属内容提供方 , 如果您对本文有版权争议 , 可与客服联系进行内容授权或下架
论文部分内容阅读
  摘要:本文阐述了Java中泛型的概念和特点,介绍了简单泛型创建和使用,探讨了泛型应用中存在的陷井。泛型最重要的特点是类型安全,泛型还可以消除类型转换等。泛型的创建和使用比较简单,但在使用中存在一定的陷阱,需要引起程序员的注意。
  关键词:泛型;类型安全;类型通配符
  中图分类号:TP311文献标识码:A文章编号:1009-3044(2007)06-11612-03
  
  1 前言
  1.1泛型概念
  Java 程序员经常会遇到使人头疼的问题――将表达式向下类型转换为比其静态类型更为具体的数据类型,这种类型转换给编程人员带来了极大的不便,同时也容易引入错误。比如,集合(Collection)中元素的类型可以是多种多样的,有些元素是Boolean 类型的,而有些则可能是Integer类型的,等等。Java 语言之所以支持多种类型元素的集合,是因为它允许程序员构建一个元素类型为Object 的 Collection。当使用Collection 时,程序员经常要做的一件事情就是强制类型转换,当转换成所需的类型以后,再对它们进行处理。在很多Java 应用中,上述情况非常普遍,为了解决这个问题,使Java 语言变得更加安全好用,Sun公司在其发布的JDK 5.0版本中引入了“泛型”这一新特性。
  泛型其实就是参数化类型,也就是把类型作为参数进行定义。泛型可以很好地解决Java中的类型转换失败的问题。我们来看两个例子。
  例1:不用泛型技术的例子。
  (1)import java.util.ArrayList;
  (2)public class MyCollection{
  (3)public static void main(String[]args){
  (4)ArrayList myStr=new ArrayList();
  (5)myStr.add("一个字符串");
  (6)String str=(String)myStr.get(0);//强制类型转换
  (7)System.out.println(str);
  (8) }
  (9) }
  例2:使用泛型技术的例子。
  (1)import java.util.ArrayList;
  (2)public class myCollection{
  (3)public static void main(String[]args){
  (4)ArrayList myStr=new ArrayList();
  (5)myStr.add("一个字符串");
  (6)String str=myStr.get(0);//没有强制类型转换。
  (7)System.out.println(str);
  (8) }
  (9)}
  在例2中,生成了一个只能包含字符串类型的ArrayList。如果你要在这个集合中添加其它类型的对象,哪么编译器会报错。这样,至少不会在运行时出现类型错误,基于大型的应用程序提高了安全性。另外,在从这个集合中取出的对像直接就是String类型,不必进行强类型转换。
  1.2泛型的特点
  (1)类型安全。 泛型的主要目标是提高Java程序的类型安全。通过使用泛型定义的变量的类型限制,编译器可以在编译时检验类型合法性。如果没有泛型,那么类型的安全性主要由程序员来把握,这显然不如带有泛型的程序安全性高。
  由于Java中所有定义的类,都以Object类为顶层类,所以JDK5.0之前,Java程序员为了让定义出来的类可以更加通用,传入的值或返回的实例都是以Object类型为主,当要取出这些实例来使用时,必须记得将之转换为原来的类型或适当的接口,这样才能使用对象上的方法。然而,对于粗心的程序员往往会忘了转换,或者转换类型或接口时用错了类型,但由于语法上是允许的,所以编译器检查不出错误,因而执行时期就会发生ClassCastException。泛型可以将类型检查从运行时挪到编译时,这有助于程序员更容易找到错误,从而提高程序的可靠性。
  (2)消除强制类型转换。 泛型的一个附带好处是,消除源代码中的许多强制类型转换。这使得代码更加可读,并且减少了出错机会。
  (3)性能收益。 泛型为较大的优化带来可能。在泛型的初始实现中,编译器将强制类型转换插入生成的字节码中(如果没有泛型,程序员要指定这些强制类型转换)。但是更多类型信息可用于编译器这一事实,为未来版本的 JVM 的优化带来可能。
  (4)擦除。泛型的实现方式采用了“擦除”方式,Java 语言中的泛型基本上完全在编译器中实现,编译器生成的代码与手工编写的不用泛型、检查程序的类型安全后进行强制类型转换所得到的代码基本相同,泛型只是更能确保类型安全。
  
  2 简单泛型的定义和使用
  2.1简单泛型类的定义
  在JDK1.5以后,Sun提出了针对泛型设计的解决方案,创建一个简单的泛型是非常容易的。首先,在一对尖括号(< >)中声明类型持有者名称,以逗号间隔类型持有者名列表。在类的实例变量和方法中,可以在任何类型的位置使用那些类型持有者名称。下面以一个简单的例子开始这部分的内容介绍。
  例3:简单泛型的定义。
  (1)import java.util.*;
  (2)public class Tree {
  (3)V value;
  (4)public Tree(V value) {this.value = value; }// 构造方法,标识类型V的使用
  (5)V getValue() {return value; }
  (6)void setValue(V value) { this.value = value; }
  (7) }
  类型持有者的命名一般使用一个大写字母,不同字母一般代表不同的含义。如T(Type)、E(Element)、V(Value)、A(Annotation)等。
  当一个变量被声明为泛型时,只能被实例变量和方法以及内部类调用,而不能被静态变量和方法调用。
  可以通过以下方式来使用泛型类。
  Tree s=new Tree("hello");
  String str=s.getValue();
  System.out.println (str);
  2.2 限制泛型可用类型
  定义泛型类时,默认可以使用任何类型来实例化泛型类中的类型持有者,但假设想要限制使用泛型类时,如何用某个特定类型或其子类型来实例化类型持有者呢?可以在定义类型持有者时,同时使用extends指定这个类型持有者实例化,实例化的对象必须继承于某个类型或实现某接口。如例3中的Tree中的类型持有者V是不受约束的,Tree可以被参数化为任何类型。如果需要强制一个类型参数实现一个或多个接口,或是一个特定类的子类,可以通过例4方式来实现。
  例4:限制泛型可用类型实例。
  (1)import java.util.*;
  (2)public class Tree> implements Comparable >{
  (3)V value;
  (4)public Tree(V value) { this.value = value; }
  (5)V getValue() { return value; }
  (6)void setValue(V value) { this.value = value; }
  (7)public int compareTo(Tree that) {
  (8)if (this.value == null && that.value == null) return 0;
  (9)if (this.value == null) return -1;
  (10)if (that.value == null) return 1;
  (11)return this.value.compareTo(that.value);
  (12) }
  (13)}
  2.3类型通配符
  仍以例3所定义的Tree来进行说明,假设使用Tree类来进行下面的声明:
  Tree tree1=null;
  Tree tree2=null;
  那么名称tree1就只能参考Tree类型的Tree实例,而tree2就只能参考Tree类型的实例。即下面形式是可行的:
  tree1=new Tree(new Integer(10));
  tree2=new Tree("ten");
  如果希望有一个变量tree可以像下面这样接受所指定的实例:
  tree=new Tree(new ArrayList());
  tree=new Tree(new LinkedList());
  即如果想要有一个tree泛型对象,其对象持有者实例化的对象是List接口的类及其子类。要声明这么一个变量,可以使用通配符(?)代表未知类型,并使用extends关键字来修饰。例如:
  Tree<? extends List> tree=null;
  tree=new Tree(new ArrayList());
  …
  tree=new Tree(new LinkedList());
  <? extends List>表示未知类型,只知道是List接口的类,所以,如果类型持有者实例化的对象不是实现List接口的类,则编译器报告错误。
  使用<?>或<? extends SomeClass>的声明方式,意味着只能通过该名称来取得泛型对象变量的信息,或者是删除某些信息,但不能增加它的信息。
  
  3 泛型使用中的陷阱
  JDK5.0增加的泛型是对类型安全的一次重大改进,泛型的创建和使用也相当简单,但是对于初次使用泛型类型的用户来说,泛型的某些方面看起来可能不容易明白,甚至非常奇怪,泛型的本身也存在一定的陷井,我们在使用中应该尽量避免。
  (1)泛型不是协变(covariant)的
  Java语言中的数组是协变的,也就是说,如果Number是Integer的超类型,那么Number[]也是Integer[]的超类型。泛型类型不是协变的,即List是List的超类型,但不能在需要 List 的地方传递 List。数组能够协变而泛型不能协变的另一个后果是,不能实例化泛型类型的数组,也就是说new List[3] 是不合法的,除非类型参数是一个未绑定的通配符,如:new List<?>[3] 是合法的。数组协变会破坏泛型的类型安全,所以不允许实例化泛型类型的数组。
  (2)构造延迟
  因为可以擦除功能,所以 List 和 List 是同一个类,编译器在编译 List 时只生成一个类。因此,在编译 List 类时,编译器不知道 V 所表示的类型,所以它就不能像知道类所表示的具体类型那样处理 List 类定义中的类型参数(List 中的 V)。
  因为运行时不能区分 List 和 List(运行时都是 List),用泛型类型参数标识类型的变量的构造就成了问题。运行时缺乏类型信息,这给泛型容器类和希望创建保护性副本的泛型类提出了难题。
  (3)类库的泛化问题
  在转化现有的库类来使用泛型方面没有多少技巧,但与平常的情况相同,向后兼容性不会凭空而来,其中向后兼容性限制了类库的泛化。
  (4)擦除方式引出的问题
  擦除意味着一个类不能同时实现 Comparable 和 Comparable,因为事实上两者都在同一个接口中,指定同一个compareTo()方法。声明 DecimalString 类以便与 String 与 Number比较似乎是明智的,但对于 Java 编译器来说,这相当于对同一个方法进行了两次声明。擦除的另一个后果是,对泛型类型参数是用强制类型转换或者instanceOf 毫无意义。擦除也是造成不能创建泛型类型的对象的原因,因为编译器不知道要调用什么构造函数。
  (5)类型受限问题
  Java 语言中的泛型不能接受基本类型作为类型参数,它只能接受引用类型。这意味着可以定义 List,但是不可以定义 List
  
  4 小结
  本文阐述了JDK1.5中新增泛型的概念和特点,介绍了简单泛型创建和使用,探讨了泛型应用中存在的陷阱。泛型解决的不只是让程序员少写几个类的程序代码,还在于让程序员定义安全的泛型类。泛型提供编译时期检查,使程序员不会因为将对象置入某个容器而失去其类型。扩展虚拟机指令集来支持泛型被认为是无法接受的,因为这会为 Java 厂商升级其 JVM 造成难以逾越的障碍。
  参考资料:
  [1]Eric(美).诊断Java代码: 轻松掌握Java泛型[M].developerWorks,2003,5.
  [2]Brian Goetz(美).Java 理论和实践:了解泛型[M].developerWorks,2005,1.
  [3]Brian Goetz(美).Introduction to generic types in JDK 5.0[M].developerWorks,2004,12.
  [4]良葛格.Java学习笔记[M].北京:清华大学出版社,2006.8.
  [5]Java 2 Platform Standard Edition 5.0 的 API 规范文档.
  本文中所涉及到的图表、注解、公式等内容请以PDF格式阅读原文。
其他文献
摘要:在分析入侵检测系统、技术以及其它正在研究的入侵检测方法的基础上,对现行入侵检测系统存在的问题进行了分析研究。  关键词:入侵检测系统,基于网络的入侵检测系统,基于主机的入侵检测系统,异常检测,误用检测  中图分类号:TP309文献标识码:A文章编号:1009-3044(2007)06-11564-01    1 引言  目前采用的入侵检测系统主要有基于网络的入侵检测系统,基于主机的入侵检测系
期刊
摘要:用VHDL语言设计交通灯控制系统,并在MAX+PLUS II系统对FPGA/CPLD芯片进行下载,由于生成的是集成化的数字电路,没有传统设计中的接线问题,所以故障率低、可靠性高,而且体积小。体现了EDA技术在数字电路设计中的优越性。  关键词:VHDL硬件描述语言;可编程逻辑器件;FPGA/CPLD;交通灯控制系统  中图分类号:TP27文献标识码:A文章编号:1009-3044(2007)
期刊
摘要:本文设计并实现了一种基于XML的电子订单安全方案,用XML加密实现了订单敏感信息的保密性,用XML签名保证了电子订单数据的完整性、身份验证性和不可否认性。对于加密、签名次序可能产生的验证错误,使用XML签名的解密变换来解决。  关键词:电子商务;XML加密;XML签名;解密变换  中图分类号:TP393文献标识码:A文章编号:1009-3044(2007)06-11569-03    1 引
期刊
摘要:超宽带(UWB)技术是目前热点研究的一种无线个域网(WPAN)技术,而其MAC协议对网络的整体性能有着极重要的作用。文中运用NS网络仿真软件搭建了完整的UWB网络环境,实现了一种融合物理层编码技术的MAC协议,并与几种传统的MAC协议进行了仿真分析比较。仿真结果表明,该协议可使网络吞吐量得到较大提高。最后提出未来设计UWB MAC协议的方向。  关键词:超宽带;无线个域网;媒体接入控制;跨层
期刊
摘要:本文研究了一种基于FPGA的WM8731的I2C配置模块的设计方案。该设计利用数字系统设计自动化(EDA)技术实现了全硬件结构的I2C配置模块的功能。系统具有集成度高、稳定性好、设计灵活和设计效率高等优点。  关键词:FPGA;I2C总线;SOPC;WM8731  中图分类号 TP391文献标识码:A文章编号:1009-3044(2007)06-11622-02    1 引言  随着SOP
期刊
摘要:由于HTTP协议的无状态性,在开发基于HTTP的B/S结构的Web应用程序时,就需要解决状态管理的问题。在ASP.NET中有客户端状态管理和服务器端状态管理两种状态管理技术。本文中通过对ASP.NET的客户端状态管理技术的特点进行分析与比较,指出了各种技术的优缺点,并给出了一些实用的使用建议。  关键词:状态管理;ASP.NET;Web应用程序  中图分类号:TP311 文献标识码:A文章编
期刊
摘要:作为PC机连接外设的接口,现在普遍应用USB和P1394接口。其中,USB是以PC机为核心的通用串行总线接口,各个结点设备受主机控制。P1394也是串行总线,可它的每个结点设备都可具有总线控制权,是目前唯一既能连接PC机外围设备,又可连接数字化AV设备的高速接口,本文从工作原理出发,介绍其工作机制,比较两者的优点和特点,从传输速度,电缆可靠性以及占用主机资源等角度进行分析比较,P1394由于
期刊
摘要:GUI能提供友好界面,使得计算机称为大多数人都能够使用和接受的工具。在一些界面功能要求简单的嵌入式系统中,可以自行编写一些函数集,来进行位图转换,图形,文字的显示以及中文的显示。文章对利用GUI的这些功能进行简单的界面设计,利用平台的键盘编写键盘控制程序实现对界面间的跳转,达到所需界面进行介绍。  关键词:Interface design;嵌入式系统;uC/GUI  中图分类号:TP311文
期刊
摘要:在分析大多数工作流管理系统的现状以及移动Agent技术特点的基础上,提出一种基于移动Agent的工作流系统架构,并利用IBM的移动Agent系统——Aglet实现原型系统。该架构采用移动Agent的安全机制,同时通过RSA公开密钥加密算法保护移动Agent所携带的信息,提高了安全性能。实践证明,基于移动Agent的工作流管理系统是可行的和先进的,能够有效地解决现有工作流管理系统中存在的效率问
期刊
摘要:S3C4510B是一种以ARM7TDMI为内核的嵌入式网络微处理器。对S3C4510B的HDLC模块的基本结构和工作原理进行了阐述,对S3C4510B的HDLC控制器驱动程序的基本设计思想及具体实现进行了研究。  关键词:S3C4510B;HDLC;驱动程序  中图分类号:TP316文献标识码:A文章编号:1009-3044(2007)06-11606-03    1 引言  HDLC作为一
期刊