正 文

Java 5.0泛型编程之泛型类型


www.7dspace.com  更新日期:2005-10-19 9:40:14  七度空间


  运行时类型安全

  就像我们所见到的,一个List<X>不允许被转换为一个List<Y>,即使这个X能够被转换为Y。然而,一个List<X>能够被转换为一个List,这样您就可以通过继承的方法来做这样的事情。

  这种将参数化类型转换为非参数化类型的能力对于向下兼容是必要的,但是它会在泛型所带来的类型安全体系上凿个漏洞:

// Here's a basic parameterized list.List<Integer> li = new ArrayList<Integer>();// It is legal to assign a parameterized type to a nonparameterized variableList l = li;   // This line is a bug, but it compiles and runs.// The Java 5.0 compiler will issue an unchecked warning about it.// If it appeared as part of a legacy class compiled with Java 1.4, however,// then we'd never even get the warning.  l.add("hello");// This line compiles without warning but throws ClassCastException at runtime.// Note that the failure can occur far away from the actual bug.Integer i = li.get(0);

  泛型仅提供了编译期的类型安全。如果您使用java5.0的编译器来编译您的代码并且没有得到任何警告,这些编译器的检查能够确保您的代码在运行期也是类型安全的。如果您获得了警告或者使用了像未经处理的类型那样修改您的集合的代码,那么您需要增加一些步骤来确保运行期的类型安全。您可以通过使用java.util.Collections中的checkedList()和checkedMap( )方法来做到这一步。这些方法将把您的集合打包成一个wrapper集合,从而在运行时检查确认只有正确类型的值能够被置入集合众。下面是一个能够补上类型安全漏洞的一个例子:

// Here's a basic parameterized list.List<Integer> li = new ArrayList<Integer>();// Wrap it for runtime type safetyList<Integer> cli = Collections.checkedList(li, Integer.class);// Now widen the checked list to the raw typeList l = cli;   // This line compiles but fails at runtime with a ClassCastException.// The exception occurs exactly where the bug is, rather than far awayl.add("hello");

  参数化类型的数组

  在使用泛型类型的时候,数组需要特别的考虑。回忆一下,如果T是S的父类(或者接口),那么类型为S的数组S[],同时又是类型为T的数组T[]。正因为如此,每次您存放一个对象到数组中时,Java解释器都必须进行检查以确保您放入的对象类型与要存放的数组所允许的类型是匹对的。例如,下列代码在运行期会检查失败,抛出一个ArrayStoreException异常:

String[] words = new String[10];Object[] objs = words;objs[0] = 1;  // 1 autoboxed to an Integer, throws ArrayStoreException

  虽然编译时obj是一个Object[],但是在运行时它是一个String[],它不允许被用于存放一个Integer。

  当我们使用泛型类型的时候,仅仅依靠运行时的数组存放异常检查是不够的,因为一个运行时进行的检查并不能够获取编译时的类型参数信息。查看下列代码:

List<String>[] wordlists = new ArrayList<String>[10];ArrayList<Integer> ali = new ArrayList<Integer>();ali.add(123);Object[] objs = wordlists;objs[0] = ali;                       // No ArrayStoreExceptionString s = wordlists[0].get(0);      // ClassCastException!

  如果上面的代码被允许,那么运行时的数组存储检查将会成功:没有编译时的类型参数,代码简单地存储一个ArrayList到一个ArrayList[]数组,非常正确。既然编译器不能阻止您通过这个方法来战胜类型安全,那么它转而阻止您创建一个参数化类型的数组。所以上述情节永远不会发生,编译器在第一行就开始拒绝编译了。

  注意这并不是一个在使用数组时使用泛型的全部的约束,这仅仅是一个创建一个参数化类型数组的约束。我们将在学习如何写泛型方法时再来讨论这个话题。

5页,页码:[1] [2] [3] [4] [5] 

上一篇:十六条超炫代码 让你的QQ空间改头换面
下一篇:谁更安全? 黑客眼中的防火墙与路由器
作者:cat  来源:Matrix ( 责任编辑:7dspace )
收藏此页】【打印】【关闭
站 内 搜 索
 

热 点 导 读
特 别 推 荐