英语原文共 44 页,剩余内容已隐藏,支付完成后下载完整资料
Java泛型的采用和使用
Chris Parnin·Christian Bird·Emerson Murphy-Hill
摘要 在2004年,Java语言中增加了对通用编程的支持,这可能是当今一种应用最广泛的编程语言所发生的最重要的变化。研究人员和语言设计师预计这种补充将缓解困扰开发者的许多长期存在的问题,但是令人惊讶的是,还没有人研究泛型如何在实践中被采用和使用。在本文中,我们通过自动挖掘40个流行的开源Java程序的历史,遍历超过6.5亿流程中的代码行,报道了关于Java泛型如何集成到开源软件中的第一次实证研究。我们针对Java开发人员如何使用泛型评估了五个假设和研究问题。例如,我们的研究结果表明,泛型有时会减少类型转换的数量,并且通常泛型会被一个项目管理者所采用,而不是所有的提交者。我们也针对为什么某些功能可能会更早被采用,而其他功能可能会被阻止提供见解。
关键词:泛型、注释、Java、语言、事后调查分析
Communicated by Arie van Deursen, Tao Xie, and Thomas Zimmermann
C. Parnin
College of Computing, Georgia Institute of Technology, Atlanta, GA 30332, USA
e-mail: chris.parnin@gatech.edu
C. Bird
Microsoft Research, Redmond, WA 98052, USA
e-mail: cbird@microsoft.com
- Murphy-Hill
Department of Computer Science,
North Carolina State University, Raleigh, NC 27695, USA
e-mail: emerson@csc.ncsu.edu
Published online: 06 December 2012
1 介绍
编程语言和工具的发展与行业趋势、革命性的转变开发者的习惯相匹配。但并非所有的演变都是成功的;技术前景充满了进化的死路和即将终止的概念的例子。
很多时候,对于新语言特征的大肆宣传和幻想都未能实现坚持或坚持实践。讨论语言功能的成本和收益很容易就会变成一场双方武装的宗教战争轶事(Markstrum 2010)。当讨论设计语言功能并考虑应该如何部署的时候,关于采用和使用过去的经验证据应该促进更加理性的讨论。搜集这种证据不仅是明智的,而且是我们团体的责任。
在本文中,我们研究了作为2004年的Java版本5而引入的泛型的采用和使用。我们首先看看例如类型声明、类型安全集合、通用方法、通配符等Java泛型的特性如何在真正的项目中被引入和使用。 凭借此研究后七年的好处,我们调查了预测、断言以及最初由研究和工业所作出的声明如何在野外展开。 此外,我们调查了采用的过程和时间表:采用旧代码的情况如何,谁来购买,这些功能多久被采用,以及有多少项目和人员忽略新功能?该结果使我们能够调整关于开发人员将如何采用未来语言功能的期望。
本文延伸了我们之前撰写的2011年MSR论文(Parnin et al. 2011)这篇论文中我们做出了以下贡献:
- 我们列举了过去关于Java泛型的假设和声明(第3节);
- 我们调查了20个开源项目如何使用或未使用Java泛型(第5-7节);
- 我们讨论泛型的采用和使用模式的含义(第9节)。
在前面的文章中,我们检查了我们研究的问题和来自既定项目视角的假设,这些项目在泛型之前就开始了。 这个视角是独一无二的,它使我们能够观察新功能在现有的代码基础上的影响。 在本文中,我们将之前的结果与近期项目的采纳模式进行对比,这些项目是在泛型之后开始的并且可能提供不同的观点。 其次,我们也想比较Java泛型的采用与另一个特性,即Java注释,它是在Java 5版本中与泛型一起发布的。 通过检查注释,可以减小风险和实现更通用的功能,我们有能力分开一些影响采用的因素; 例如,Java虚拟机的兼容性是主要的采用障碍,还是其他的东西?
在本文中,我们添加了以下新的贡献:
- 我们探索引入泛型之后启动的20个新的开源项目;
- 我们将有关泛型的发现与另一种语言功能(Java注释)的数据进行对比。
2 语言功能概述
在本节中,我们将简要介绍Java泛型和注释的动机和使用。 为了保持一致的术语,我们以粗体显示我们在本文中使用的术语,并尽可能使用标准术语。熟悉Java泛型和注释的读者可以地跳过这一部分。
-
- 泛型的动机
在诸如Java之类的编程语言中,类型系统可以确保某些类型的运行错误不会发生。 例如,考虑以下Java代码:
List I = getList();
System.out.println(I.get(10));
该代码将打印列表的第10个元素的值。 类型系统确保无论getList()返回什么对象,它都会理解get消息,并且调用该方法时不会出现运行错误。这样,类型系统在编译时提供安全保证,以避免错误出现运行。
现在假设我们想要进一步推进这个例子;假设我们知道I包含File类型的对象,我们想知道列表中第10个文件是否是一个目录。 我们可能自然而然地(尽管是错误的)这样写:
List I = getList();
System.out.println(I.get(10).isDirectory());
不幸的是,这会导致编译错误,因为get方法的返回类型在编译时被指定为Object。 类型检查器给出错误是因为它不知道列表中实际存在哪些类型的对象。
在Java早期,程序员有两种方法来解决这个问题,第一种是投影,第二个我们称之为本土数据结构。 如果程序员执行投影解决方案,代码将如下所示:
List I = getList();
System.out.println(((File)I.get(10)).isDirectory());
投影是(File)部分,这迫使编译器意识到表达式l.get(10)实际上被认为是File类型。虽然这解决了一个问题,它导致另一个问题; 假设某个程序员稍后忘记了该列表的目的是保存文件,并无意中在List中放入一个String类型变量。然后当这段代码被执行时,运行时异常将会在投影中被抛出。一个相关的问题是代码不够清晰,因为程序中没有任何地方明确指定getList()包含的列表返回何种类型的对象。
如果程序员改为实施本土数据结构解决方案,代码将如下所示:
FileList I = getList();
System.out.println(I.get(10).isDirectory());
另外,程序员需要创建一个FileList类。此解决方案也引入了新的问题。也许最重要的是代码爆炸问题;对于包含不同类型的每个列表,程序员都会想要创建一个不同的特殊列表类,如StringList,IntegerList,和NodeList。这些类将不可避免地包含重要的重复,因为它们都执行相同的功能,只有数据类型不同。
-
- 泛型编程
随着2004年泛型引入Java,这些问题得到了解决。泛型允许程序员创建自己的泛型类型声明(Bracha2012)(我们简称为通用类型)。 例如,程序员可以像这样为一个列表创建用户定义的通用声明:
class MyListlt;Tgt;{
List internal;
public T get(int index){
return (T)internal.get(index);
} hellip;
在这段代码中,T被称为形式类型参数。程序员可以通过使用一个类型参数来实例化形式类型参数,从而使用它的MyList类(Bracha 2012),例如以下示例中的Integer或File:
MyListlt;Integergt;intList = new MyListlt;Integergt;();
MyListlt;Filegt;fileList = new MyListlt;Filegt;();
调用泛型类型声明的每个地方(在此示例中是4处)被称为参数化类型(Bracha 2005)。 在第一行中,程序员已经声明了intList对象的类型,以便编译器知道它包含Integer类型的对象,因此表达式intList.get(10)将是Integer类型。 结果客户端代码的这两种类型都是安全的,并且清楚地表达了程序员的意图。 程序员也可以在不使用泛型作为原始类型的情况下,使用泛型类型声明,比如MyList objectList,在这种情况下表达式objectList.get(10)将是Object类型的。
除了创建自己的泛型类型声明外,程序员还可以使用来自库的泛型类型声明。 例如,Sun的软件开发人员(Bracha 2005),或转入到使用泛型,即Java集合类。例如,List类被参数化,所以前面的问题也可以这样解决:
Listlt;Filegt; I = getList();
System.out.println(I.get(10).isDirectory());
除了在类型声明中使用泛型外,泛型也可以应用于个别方法来创建泛型方法,如下所示:
lt;Agt; A head(Listlt;Agt; I){
return I.get(0);
}
在这段代码中,程序员可以向head方法传递一个包含任何类型的通用列表。
-
- 注释动机
程序员有时希望他们的软件为运行在软件上的工具提供信息。 例如,一个程序可能想要告诉编译器某种方法已被弃用并且不应再被调用(Java语言指南2012)或者一个类可能想告诉它的环境它代表一个Web服务(Java EE 5平台2012的优势)。 在Java 5之前,这样的与工具交流的机制是特设的。 例如,在Java 5之前,JavaDoc注释中的弃用标记指示方法是否被弃用,而外部描述符文件则表明一个类是Web服务。
-
- 用注释编程
对于Java 5,注释语言功能是作为一个统一的语法引入的向工具发布指令的程序。使用注释的方法为程序员将一个@符号放置在程序元素之前的注释名称的前面(例如一个类或方法),并且如果注释具有值,则将这些值设置在括号中。例如,为了告诉编译器head方法已被废弃,程序员可以编写以下内容:
@Deprecated
lt;Agt; A head(Listlt;Agt; I){
编译程序时,编译器会警告程序员引用此方法的任何代码。 如果程序员想要将一个类标记为Web服务,他可以像下面这样编程:
@WebService
Public class MyWebService{
@Deprecated注释是一个被Java 5编译器识别的例子。编译器默认识别的两个其他注释:@Override注解,用于指示方法在超类中重写,和@SuppressWarnings注解,用于告诉编译器不要在编译时产生某些警告(Java教程2012)。@WebService注释是一个在特定API中定义的注释的例子。通常这些类型的注释被发现和检查反射和用于诸如自动生成包装代码或配置框架属性。用户可以将自己的习惯注释定义为well,尽管讨论如何完成这件事超出了本文的范围。
3 相关工作
在本节中,我们将讨论先前关于泛型的声明和研究。
-
- 关于泛型的声明
当Sun引入泛型时,他们声称语言特征是“对类型系统期待已久的改进”,它“消除了铸造的苦差事。”Sun建议程序员“应该在他们能够使用的任何地方使用泛型。代码生成中的额外努力在代码清晰度和类型安全上都是值得的。”已有多篇文章和书籍赞扬了在几种情况下使用泛型的好处。 我们在这里列出一个例子。
在Effective Java中,Bloch(2008)声称,当程序员使用非泛型时,在运行时间之前他不会发现错误。 更糟的是,错误是当从一个集合中取出一个项目时,它显示为一个ClassCastException。为了纠正错误,他必须费时地识别哪个对象错误地插入集合中。 通过使用泛型,类型系统为开发人员精确地显示出他在哪里插入了不正确的对象,从而减少了解决问题的时间
全文共8939字,剩余内容已隐藏,支付完成后下载完整资料
资料编号:[16650],资料为PDF文档或Word文档,PDF文档可免费转换为Word
以上是毕业论文外文翻译,课题毕业论文、任务书、文献综述、开题报告、程序设计、图纸设计等资料可联系客服协助查找。