详解java的泛型

上传人:pu****.1 文档编号:564333156 上传时间:2023-03-05 格式:DOC 页数:15 大小:102.50KB
返回 下载 相关 举报
详解java的泛型_第1页
第1页 / 共15页
详解java的泛型_第2页
第2页 / 共15页
详解java的泛型_第3页
第3页 / 共15页
详解java的泛型_第4页
第4页 / 共15页
详解java的泛型_第5页
第5页 / 共15页
点击查看更多>>
资源描述

《详解java的泛型》由会员分享,可在线阅读,更多相关《详解java的泛型(15页珍藏版)》请在金锄头文库上搜索。

1、java泛型详解泛型 (Gen eric t ype 或者 gen erics ) 是对 J ava 语言的类 型系统的一种扩展,以支持创建可以按类型进行参数化的类。可 以把类型参数看作是使用参数化类型时指定的类型的一个占位 符,就像方法的形式参数是运行时传递的值的占位符一样。可以在集合框架(Collection framework)中看到泛型的动 机。例如,Map类允许您向一个Map添加任意类的对象,即使最 常见的情况是在给定映射(map)中保存某个特定类型(比如 St r i ng)的对象。因为Map. get ()被定义为返回Obj ect,所以一般必须将 Map. get ()的结果强

2、制类型转换为期望的类型,如下面的代码所 示:Map m = new Has hMap();m.put(key, bl ar g);St r i ng s = ( St r i ng) m. get ( key);要让程序通过编译,必须将get ()的结果强制类型转换为St r i ng,并且希望结果真的是一个St r i ng。但是有可能某人已经 在该映射中保存了不是Stri ng的东西,这样的话,上面的代码将 会抛出 Cl as sCast Except i on。理想情况下,您可能会得出这样一个观点,即m是一个Map, 它将St r i ng键映射到St r i ng值。这可以让您消除代码

3、中的强制 类型转换,同时获得一个附加的类型检查层,该检查层可以防止 有人将错误类型的键或值保存在集合中。这就是泛型所做的工作。泛型的好处Java语言中引入泛型是一个较大的功能增强。不仅语言、 类型系统和编译器有了较大的变化,以支持泛型,而且类库也进 行了大翻修,所以许多重要的类,比如集合框架,都已经成为泛 型化的了。这带来了很多好处:类型安全。泛型的主要目标是提高Java程序的类型安 全。通过知道使用泛型定义的变量的类型限制,编译器可以在一 个高得多的程度上验证类型假设。没有泛型,这些假设就只存在 于程序员的头脑中(或者如果幸运的话,还存在于代码注释中)。Java程序中的一种流行技术是定义这样

4、的集合,即它的元 素或键是公共类型的,比如“ St r i ng列表”或者“ St r i ng到St r i ng 的映射”。通过在变量声明中捕获这一附加的类型信息,泛型允 许编译器实施这些附加的类型约束。类型错误现在就可以在编译 时被捕获了,而不是在运行时当作Cl ass Cast Except io n展示出 来。将类型检查从运行时挪到编译时有助于您更容易找到错误, 并可提高程序的可靠性。消除强制类型转换。泛型的一个附带好处是,消除源代码 中的许多强制类型转换。这使得代码更加可读,并且减少了出错机会尽管减少强制类型转换可以降低使用泛型类的代码的罗嗦程 度,但是声明泛型变量会带来相应的罗嗦

5、。比较下面两个代码例 子。该代码不使用泛型:Li st l i = n ew Ar r ay Li st ();l i. put ( new I nt eger ( 3);In t eger i = (In t eger) l i. get(O);该代码使用泛型:Li st l i = new Ar r ay Li st ();l i. put ( new I nt eger ( 3);I nt eger i = l i. get ( 0);在简单的程序中使用一次泛型变量不会降低罗嗦程度。但是 对于多次使用泛型变量的大型程序来说,则可以累积起来降低罗 嗦程度。潜在的性能收益。泛型为较大的优化带

6、来可能。在泛型的 初始实现中,编译器将强制类型转换(没有泛型的话,程序员会 指定这些强制类型转换)插入生成的字节码中。但是更多类型信 息可用于编译器这一事实,为未来版本的J VM的优化带来可能。由于泛型的实现方式,支持泛型(几乎)不需要JVM或类文 件更改。所有工作都在编译器中完成,编译器生成类似于没有泛 型(和强制类型转换)时所写的代码,只是更能确保类型安全而 已。泛型用法的例子泛型的许多最佳例子都来自集合框架,因为泛型让您在保存 在集合中的元素上指定类型约束。考虑这个使用Map类的例子, 其中涉及一定程度的优化,即Map. get ()返回的结果将确实是一 个 St r i ng :Map

7、 m = new Has hMap();m.put(key, bl ar g);St r i ng s = ( St r i ng) m. get ( key);如果有人已经在映射中放置了不是St r i ng的其他东西,上面 的代码将会抛出Cl ass Cast Ex cept i on。泛型允许您表达这样的类 型约束,即m是一个将St r i ng键映射到St r i ng值的Map。这可 以消除代码中的强制类型转换,同时获得一个附加的类型检查层, 这个检查层可以防止有人将错误类型的键或值保存在集合中。下面的代码示例展示了 JDK5. 0中集合框架中的Map接口 的定义的一部分:publ

8、i c i nt erf ace Map publ i c voi d put ( K key, V val ue);publ i c V get ( K key);注意该接口的两个附加物:*类型参数K和 V在类级别的规格说明,表示在声明一个 Map类型的变量时指定的类型的占位符。*在 get()、put ()和其他方法的方法签名中使用的 K和 V。为了赢得使用泛型的好处,必须在定义或实例化Map类型的 变量时为K和V提供具体的值。以一种相对直观的方式做这件事:MapvSt r i ng, St r i ng m = new HashMapvStri ng, S t r i n g();m.p

9、ut(key, bl ar g);St r i ng s = m. get ( key);当使用Map的泛型化版本时,您不再需要将Map. get ()的结 果强制类型转换为Stri ng ,因为编译器知道get ()将返回一个 St r i ng。在使用泛型的版本中并没有减少键盘录入;实际上,比使用 强制类型转换的版本需要做更多键入。使用泛型只是带来了附加 的类型安全。因为编译器知道关于您将放进Map中的键和值的类 型的更多信息,所以类型检查从执行时挪到了编译时,这会提高 可靠性并加快开发速度。向后兼容在Java语言中引入泛型的一个重要目标就是维护向后兼 容。尽管JDK 5. 0的标准类库中

10、的许多类,比如集合框架,都 已经泛型化了,但是使用集合类(比如HashMbp和Ar r ay Li st ) 的现有代码将继续不加修改地在 J DK 5. 0中工作。当然,没有 利用泛型的现有代码将不会赢得泛型的类型安全好处。类型参数在定义泛型类或声明泛型类的变量时,使用尖括号来指定形 式类型参数。形式类型参数与实际类型参数之间的关系类似于形 式方法参数与实际方法参数之间的关系,只是类型参数表示类型, 而不是表示值。泛型类中的类型参数几乎可以用于任何可以使用类名的地 方。例如,下面是j ava. ut i l. Map接口的定义的摘录:publ i c i nt erf ace Map pub

11、l i c voi d put ( K key, V val ue);publ i c V get ( K key);Map接口是由两个类型参数化的,这两个类型是键类型K和 值类型V。(不使用泛型)将会接受或返回Obj ect的方法现在在 它们的方法签名中使用K或V,指示附加的类型约束位于Map的 规格说明之下。当声明或者实例化一个泛型的对象时,必须指定类型参数的MapvStr ing, St r ing map = new HashMap();注意,在本例中,必须指定两次类型参数。一次是在声明变 量map的类型时,另一次是在选择Ha sh Ma p类的参数化以便可以 实例化正确类型的一个实例

12、时。编译器在遇到一个 MapvStri ng, St r i ng类型的变量时,知 道K和V现在被绑定为St r i ng,因此它知道在这样的变量上调用 Map. get ()将会得到 St r i ng类型。除了异常类型、枚举或匿名内部类以外,任何类都可以具有 类型参数。命名类型参数推荐的命名约定是使用大写的单个字母名称作为类型参数。 这与C+约定有所不同(参阅附录 A:与C+模板的比较), 并反映了大多数泛型类将具有少量类型参数的假定。对于常见的 泛型模式,推荐的名称是:* K键,比如映射的键。* V值,比如 Li st 和 Set 的内容,或者 Map 中的 值。* E异常类。* T泛型

13、。泛型不是协变的关于泛型的混淆,一个常见的来源就是假设它们像数组一样是协变的。其实它们不是协变的。Li st 不是Li st 的父类型。如果 A扩展 B,那么 A的数组也是 B的数组,并且完全 可以在需要B的地方使用A:In t ege r in t Ar r ay =n ew I nteger10;Number nu mber Ar r ay = in tArray;上面的代码是有效的,因为一个In t eger是一个 Number,因 而一个In t eger数组是一个Number数组。但是对于泛型来说则不 然。下面的代码是无效的:Li st in t Li st = n ew Ar r

14、ay Li st ();Li st nu mbe r Li st = in t Li st ; / / i nv al i d最初,大多数Java程序员觉得这缺少协变很烦人,或者甚 至是“坏的(broken) ”,但是之所以这样有一个很好的原因。如果可以将Li st 赋给Li st ,下面的代码就会 违背泛型应该提供的类型安全:Li st in t Li st = n ew Ar r ay Li st ();Li st nu mbe r Li st = in t Li st ; / / i nv al i dnu mber Li st. add (new Fl oat ( 3. 1415);因

15、为in t Li st和number Li st都是有别名的,如果允许的话, 上面的代码就会让您将不是In t eger s的东西放进in t Li st中。但 是,正如下一屏将会看到的,您有一个更加灵活的方式来定义泛package com. i bm.course, gen er i cs;i mpo r t j ava. util. Ar r ay Li st ;i mpor t j ava. util. Li st ;publ i c cl ass GenericsExample publ i c st at i c voi d main (Str in g ar gs) In t ege r in t eger =n ew I nteger5;Number nu mber = in t eger;Sy st em. out. prin

展开阅读全文
相关资源
相关搜索

当前位置:首页 > 办公文档 > 解决方案

电脑版 |金锄头文库版权所有
经营许可证:蜀ICP备13022795号 | 川公网安备 51140202000112号