java中得泛型Word文件下载.docx

上传人:b****6 文档编号:18365393 上传时间:2022-12-15 格式:DOCX 页数:17 大小:34.20KB
下载 相关 举报
java中得泛型Word文件下载.docx_第1页
第1页 / 共17页
java中得泛型Word文件下载.docx_第2页
第2页 / 共17页
java中得泛型Word文件下载.docx_第3页
第3页 / 共17页
java中得泛型Word文件下载.docx_第4页
第4页 / 共17页
java中得泛型Word文件下载.docx_第5页
第5页 / 共17页
点击查看更多>>
下载资源
资源描述

java中得泛型Word文件下载.docx

《java中得泛型Word文件下载.docx》由会员分享,可在线阅读,更多相关《java中得泛型Word文件下载.docx(17页珍藏版)》请在冰豆网上搜索。

java中得泛型Word文件下载.docx

在散列表上执行插入和检索操作的类型特征符告诉我们只能插入和删除任意对象。

例如,put和get操作的说明如下所示:

  清单1.插入/检索类型说明表明只能是任意对象

classHashtable{

 Objectput(Objectkey,Objectvalue){...}

 Objectget(Objectkey){...}

 ...

}

  因此,当我们从类Hashtable的实例检索元素时,比如,即使我们知道在Hashtable中只放了String,而类型系统也只知道所检索的值是Object类型。

在对检索到的值进行任何特定于String的操作之前,必须将它强制转换为String,即使是将检索到的元素添加到同一代码块中,也是如此!

  清单2.将检索到的值强制转换成String

importjava.util.Hashtable;

classTest{

 publicstaticvoidmain(String[]args){

  Hashtableh=newHashtable();

  h.put(newInteger(0),"

value"

);

  Strings=(String)h.get(newInteger(0));

  System.out.println(s);

 }

  请注意main方法主体部分的第三行中需要进行的数据类型转换。

因为Java类型系统相当薄弱,因此代码会因象上面那样的数据类型转换而漏洞百出。

这些数据类型转换不仅使Java代码变得更加拖沓冗长,而且它们还降低了静态类型检查的价值(因为每个数据类型转换都是一个选择忽略静态类型检查的伪指令)。

我们该如何扩展该类型系统,从而不必回避它呢?

  用泛型类型来解决问题!

要消除如上所述的数据类型转换,有一种普遍的方法,就是用泛型类型来增大Java类型系统。

可以将泛型类型看作是类型“函数”;

它们通过类型变量进行参数化,这些类型变量可以根据上下文用各种类型参数进行实例化。

例如,与简单地定义类Hashtable不同,我们可以定义泛型类Hashtable<

Key,Value>

,其中Key和Value是类型参数。

除了类名后跟着尖括号括起来的一系列类型参数声明之外,在Tiger中定义这样的泛型类的语法和用于定义普通类的语法很相似。

例如,可以按照如下所示的那样定义自己的泛型Hashtable类:

  清单3.定义泛型Hashtable类

classHashtable<

{...}

  然后可以引用这些类型参数,就像我们在类定义主体内引用普通类型那样,如下所示:

  清单4.像引用普通类型那样引用类型参数

{

 Valueput(Keyk,Valuev){...}

 Valueget(Keyk){...}

  类型参数的作用域就是相应类定义的主体部分(除了静态成员之外)(在下一篇文章中,我们将讨论为何Tiger实现中有这样的“怪习”,即必须对静态成员进行此项限制。

请留意!

)。

  创建一个新的Hashtable实例时,必须传递类型参数以指定Key和Value的类型。

传递类型参数的方式取决于我们打算如何使用Hashtable。

在上面的示例中,我们真正想要做的是创建Hashtable实例,它只将Integer映射为String。

可以用新的Hashtable类来完成这件事:

  清单5.创建将Integer映射为String的实例

  Hashtable<

Integer,String>

h=newHashtable<

();

  ...

现在不再需要数据类型转换了。

请注意用来实例化泛型类Hashtable的语法。

就像泛型类的类型参数用尖括号括起来那样,泛型类型应用程序的参数也是用尖括号括起来的。

  清单6.除去不必要的数据类型转换

...

Strings=h.get("

key"

System.out.println(s);

  当然,程序员若只是为了能使用泛型类型而必须重新定义所有的标准实用程序类(比如Hashtable和List)的话,则可能会是一项浩大的工程。

幸好,Tiger为用户提供了所有Java集合类的泛型版本,因此我们不必自己动手来重新定义它们了。

此外,这些类能与旧代码和新的泛型代码一起无缝工作(下个月,我们会说明如何做到这一点)。

  Tiger的基本类型限制

  Tiger中类型变量的限制之一就是,它们必须用引用类型进行实例化-基本类型不起作用。

因此,在上面这个示例中,无法完成创建从int映射到String的Hashtable。

  这很遗憾,因为这意味着只要您想把基本类型用作泛型类型的参数,您就必须把它们组装为对象。

另一方面,当前的这种情况是最糟的;

您不能将int作为键传递给Hashtable,因为所有的键都必须是Object类型。

  我们真正想看到的是,基本类型可以自动进行包装(boxing)和解包装(unboxing),类似于用C#所进行的操作(或者比后者更好)。

遗憾的是,Tiger不打算包括基本类型的自动包装(但是人们可以一直期待Java1.6中出现该功能!

  受限泛型

  有时我们想限制可能出现的泛型类的类型实例化。

在上面这个示例中,类Hashtable的类型参数可以用我们想用的任何类型参数进行实例化,但是对于其它某些类,我们或许想将可能的类型参数集限定为给定类型范围内的子类型。

例如,我们可能想定义泛型ScrollPane类,它引用普通的带有滚动条功能的Pane。

被包含的Pane的运行时类型通常会是类Pane的子类型,但是静态类型就只是Pane。

  有时我们想用getter检索被包含的Pane,但是希望getter的返回类型尽可能具体些。

我们可能想将类型参数MyPane添加到ScrollPane中,该类型参数可以用Pane的任何子类进行实例化。

然后可以用这种形式的子句:

extendsBound来说明MyPane的声明,从而来设定MyPane的范围:

  清单7.用extends子句来说明MyPane声明

classScrollPane<

MyPaneextendsPane>

  当然,我们可以完全不使用显式的范围,只要能确保没有用不适当的类型来实例化类型参数。

  为什么要自找麻烦在类型参数上设定范围呢?

这里有两个原因。

首先,范围使我们增加了静态类型检查功能。

有了静态类型检查,就能保证泛型类型的每次实例化都符合所设定的范围。

  其次,因为我们知道类型参数的每次实例化都是这个范围之内的子类,所以可以放心地调用类型参数实例出现在这个范围之内的任何方法。

如果没有对参数设定显式的范围,那么缺省情况下范围是Object,这意味着我们不能调用范围实例在Object中未曾出现的任何方法。

  多态方法

  除了用类型参数对类进行参数化之外,用类型参数对方法进行参数化往往也同样很有用。

泛型Java编程用语中,用类型进行参数化的方法被称为多态方法(Polymorphicmethod)。

  多态方法之所以有用,是因为有时候,在一些我们想执行的操作中,参数与返回值之间的类型相关性原本就是泛型的,但是这个泛型性质不依赖于任何类级的类型信息,而且对于各个方法调用都不相同。

例如,假定想将factory方法添加到List类中。

这个静态方法只带一个参数,也将是List唯一的元素(直到添加了其它元素)。

因为我们希望List成为其所包含的元素类型的泛型,所以希望静态factory方法带有类型变量T这一参数并返回List<

T>

的实例。

  但是我们确实希望该类型变量T能在方法级别上进行声明,因为它会随每次单独的方法调用而发生改变(而且,正如我在下一篇文章中将讨论的那样,Tiger设计的“怪习”规定静态成员不在类级类型参数的范畴之内)。

Tiger让我们通过将类型参数作为方法声明的前缀,从而在单独的方法级别上声明类型参数。

例如,可以按照如下所示的那样为factory方法make添加前缀:

  清单8.将类型参数作为前缀添加到方法声明

classUtilities{

 <

TextendsObject>

publicstaticList<

make(Tfirst){

  returnnewList<

(first);

 }

  除了多态方法中所增加的灵活性之外,Tiger中还增加了一个优点。

Tiger使用类型推断机制,根据参数类型来自动推断出多态方法的类型。

这可以大大减少方法调用的繁琐和复杂性。

例如,如果想调用make方法来构造包含newInteger(0)的List<

Integer>

新实例,那么只需编写:

  清单9.强制make构造新实例

Utilities.make(Integer(0))

  然后会自动地从方法参数中推断出类型参数的实例化。

  结束语

  正如我们所见到的那样,在Java语言中添加泛型类型肯定会大大增强我们使用静态类型系统的能力。

学习如何使用泛型类型相当简单,但是同样也需要避免一些缺陷。

在接下来的文章中,我们将讨论如何充分使用将出现在Tiger中的泛型类型的特定表现,以及一些缺陷。

我们还将研究对泛型Java类型工具的扩展,我们期盼这些工具可以出现在仍处于设计阶段的Java平台之中。

J2SE1.5―代号为“Tiger”―计划在2003年年底发布,它将包括泛型类型(如在JSR-14原型编译器中预先展示的那样,现在可下载获得)。

在第1部分中,我们讨论了泛型类型的基础知识,以及为什么它们是对Java语言的一个重要且迫切需要的补充。

我们还说明了为Tiger制定的泛型类型的实现怎么会包含数个“缺陷”,这些缺陷限制了可以使用泛型类型的上下文。

  为了帮助新程序员有效地使用泛型类型,我将详细说明到底泛型类型的哪些用法在Tiger和JSR-14中是被禁止的,并将说明为什么这些限制是JSR-14(理所当然还有Tiger)为了在JVM上兼容地实现泛型类型所使用的实现策略的必然结果。

  泛型类型的限制

  让我们先查阅一下Tiger和JSR-14中泛型类型的使用限制:

  不应在静态成员中引用封闭类型参数。

  不能用基本类型实例化泛型类型参数。

  不能在数据类型转换或instanceof操作中使用“外露”类型参数。

  不能在new操作中使用“外露”类型参数。

  不能在类定义的implements或extends子句中使用“外露”类型参数。

  为什么会有这些限制呢?

这要归因于Tiger和JSR-14为在JVM上实现泛型类型所使用的机制。

由于JVM根本不支持泛型类型,所以这些编译器“耍了个花招”,使得似乎存在对泛型类型的支持―它们用泛型类型信息检查所有的代码,但随即“擦除”所有的泛型类型并生成只包含普通类型的类文件。

  例如,将象List<

这样的泛型类型擦除得只剩下List。

“外露”类型参数―单独出现而不是位于某个类型中的类型参数(如类List<

中的类型参数T)―被简单地擦除成它们的上界(就T而言,其上界就是Object)。

强大;

我们可以使几乎所有泛型类型的精度得到增强,但又与JVM保持兼容。

事实上,我们甚至可以交替地使用非泛型的旧类(比如List)和其对应的泛型类(List<

);

两者在运行时看起来是一样的。

  遗憾的是,正如以上的限制所示,获得这一功能是有代价的。

以这种方式进行擦除在类型系统中引入了缺陷,这些缺陷限制我们使用泛型类型的安全性。

  为了帮助说明每种限制,我们查阅会出现这些限制的示例。

在本文中,我们将讨论前三个限制。

与后两个限制有关的问题过于复杂,因而需要更深入的研究,留待下一篇文章讨论。

  静态成员中的封闭类型参数

  编译器完全禁止在静态方法和静态内部类中引用封闭类型参数。

所以,举例来说,以下代码在Tiger中就是非法的:

  清单1.在静态上下文中非法引用封闭类型参数

classC<

 staticvoidm(){

  Tt;

 staticclassD{

  C<

t;

  当编译这一代码时,会生成两个错误:

  在静态方法m中非法引用T的错误

  在静态类D中非法引用T的错误

  当定义静态字段时,情况变得更加复杂。

在JSR-14和Tiger中,在泛型类的所有实例中共享该类中的静态字段。

现在,在JSR-14编译器1.0和1.2中,如果您在静态字段声明中引用类型参数,编译器不会报错,但它本应该这么做。

字段被共享这一事实很容易在运行时导致奇怪的错误,如在不包含数据类型转换的代码中出现ClassCastException。

  例如,以下程序将在这两个版本的JSR-14下通过编译而没有任何警告:

  清单2.在静态字段中对封闭类型参数的有问题的引用

这个月,EricAllen继续讨论JSR-14和Tiger中的泛型类型(generictype)。

他概括了在这些Java扩展中强制实施的几个限制,并说明这些扩展语言的编译器所使用的实现策略如何使这些限制必然存在。

 staticTmember;

 C(Tt){member=t;

}

 TgetMember(){returnmember;

String>

c=newC<

("

test"

  System.out.println(c.getMember().toString());

  newC<

(newInteger

(1));

  请注意,每次分配类C的实例时,都要重新设置静态字段member。

而且,它被设置成的对象类型取决于C的实例的类型!

在所提供的main方法中,第一个实例c是C<

类型。

而第二个是C<

每当从c访问member这一共享静态字段时,总是假定member的类型是String。

但是,在分配了类型为C<

的第二个实例之后,member的类型是Integer。

  运行C的main方法的结果可能会让您吃惊―它将发出一个ClassCastException!

源代码根本没有包含任何数据类型转换,怎么会这样呢?

事实证明编译器确实在编译阶段将数据类型转换插入到代码中,这样做是为了解决类型擦除会降低某些表达式的类型的精度这一事实。

这些数据类型转换被期望能够成功,但在本例中却没有成功。

  应该认为JSR-141.0和1.2的这一特殊“功能”是个错误。

它破坏了类型系统的健全性,或者可以说,它破坏了类型系统应该和程序员达成的“基本契约”。

象对静态方法和类所做的那样,只要防止程序员在静态字段中引用泛型类型,情况就会好很多。

  请注意允许这种有潜在“爆炸性”的代码存在所带来的问题并不是程序员有意在自己的代码中覆盖类型系统。

问题是程序员可能会无意中编写这样的代码(比如,由于“复制和粘贴”操作,错误地在字段声明中包括静态修饰符)。

类型检查器应该能帮助程序员从这些类型的错误中恢复,但对于静态字段而言,类型系统实际上会使程序员更迷惑。

当未使用数据类型转换的代码中显示的唯一错误就是ClassCastException时,我们应如何诊断这样的错误?

对于不清楚Tiger中泛型类型所用的实现方案而又恰好假定类型系统合理运行的程序员而言,情况更糟。

因为在这样的情况下,类型系统不是合理地运行。

  幸运的是,JSR-14的最新版本(1.3)宣布在静态字段中使用类型参数是不合法的。

因此,我们有理由期待在Tiger的静态字段中使用类型参数也是不合法的。

  泛型类型参数和基本类型

  和我们刚才讨论的不同,这一限制没有同样的潜在缺陷,但它会使您的代码非常冗长。

例如,在java.util.Hashtable的泛型版本中,有两种类型参数:

用于Key类型的和用于Value类型的。

因此,如果我们想要一个将String映射到String的Hashtable,我们可以用表达式newHashtable<

String,String>

()指定新的实例。

但是,如果我们想要一个将String映射到int的Hashtable,我们只能创建Hashtable<

String,Integer>

的实例,并将所有的int值包装在Integer中。

  同样,Tiger在这方面当然也是由所用的实现方案得到的。

既然类型参数被擦除为它们的界限,而界限不能是基本类型,所以一旦类型被擦除,则对基本类型的实例化会完全没有意义。

  数据类型转换或instanceof操作中的“外露”参数

  回想一下,对于“外露”类型参数,我们是指在词汇上单独出现的类型参数,而不是更大类型的语法子组件。

例如,C<

不是“外露”类型参数,但(在C主体中)T是。

  如果在代码中对“外露”类型参数进行数据类型转换或instanceof操作,则编译器将发出名为“unchecked”的警告。

例如,以下代码将生成警告:

Warning:

uncheckedcasttotypeT:

清单3.带unchecked操作的泛型代码

interfaceRegistry{

 publicvoidregister(Objecto);

implementsRegistry{

 intcounter=0;

 Hashtable<

Integer,T>

values;

 publicC(){

  values=newHashtable<

 publicvoidregister(Objecto){

  values.put(newInteger(counter),(T)o);

  counter++;

  您应该严肃地对待这些警告,因为它们说明您的代码在运行时会表现得非常奇怪。

事实上,它们会使得诊断代码变得极为困难。

在以前的代码中,我们认为如果对实例C<

JFrame>

调用register("

),会发出ClassCastException。

但并非如此;

计算将继续,就仿佛数据类型转换成功了一样,然后在进一步进行计算时发出错误,或者更糟:

用遭破坏的数据完成计算,但不向外发出任何错误信号。

同样,对“外露”类型参数的instanceof检查将在编译时产生“unchecked”警告,而且检查将不会如期在运行时进行。

  双刃剑

  那么,这里到底发生了什么?

因为Tiger依靠类型擦除,所以数据类型转换和instanceof测试中的外露类型参数被“擦除”为它们的上界(在前面的例子中

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 自然科学 > 生物学

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1