• 欢迎访问天天编码网站,Java技术、技术书单、开发工具,欢迎加入天天编码
  • 如果您觉得本站非常有看点,那么赶紧使用Ctrl+D 收藏天天编码吧
  • 我们的淘宝店铺已经开张了哦,传送门:https://shop145764801.taobao.com/

深入讲解Java的泛型擦除机制

Java高级 tiantian 1942次浏览 1个评论 扫描二维码

Java的泛型机制是在 JDK 5 中引入的一个重要特性。这个特性允许我们在定义 类(Class) 和 接口(Interface) 的时候,可以使用 类型参数(type parameter)。而且,泛型机制被广泛地应用在JDK的集合框架(Collection framework)中。泛型机制有着这样、那样的好处,但是对于初学者来说,泛型机制可能不好理解,特别是其中的 泛型擦除(Type Erasure)部分。本文将迎难而上,详细解释泛型擦除的概念并帮助大家掌握其用法。

深入讲解Java的泛型擦除机制

常犯错误

在详细阐述泛型擦除机制之前,我们先来看一个简单的代码示例:我们定义了一个方法 accetp ,该方法接受一个元素类型为 Object 的 List作为其参数。在 main 方法中,我们使用一个元素类型为 String 的 List 作为参数调用该方法。大家先仔细思考一下该方法是否正确?

public class Main {
public static void main(String[] args) throws IOException {
ArrayList al = new ArrayList();
al.add("a");
al.add("b");

accept(al);
}

public static void accept(ArrayList<object width="300" height="150"> al){for(Object o: al)System.out.println(o);}}```这个示例代码在表面看来似乎是正确的,因为 Object 确实是 String 类型的父类。然后,该示例代码无法获得期望的输出结果。在代码编译时就通不过,在 accetp(al) 这一行抛出一个如下所示的错误信息:```The method accept(ArrayList &lt; Object &gt; ) in the type Main is not applicable for the arguments(ArrayList &lt; String &gt; )```#### List&lt; Object &gt; vs List&lt; String &gt;造成上述编译出错的原因就是Java中的泛型擦除机制。注意:Java的泛型机制只存在编译层面。在编译器生成的字节码中是没有任何泛型类型相关的信息,运行时,自然看不到任何的泛型信息。在编译过后,List&lt; String &gt; 变成了 List,相当于一个 Object,而 accept方法的要求的参数类型是 List&lt; Object &gt; ,这就造成了我们上述看到的这个奇怪编译错误信息。在编译阶段,编译器发现实参和形参不是同一个类型,所以抛出来一个编译错误信息。#### 通配符(wildcard)泛型的通配符是 "?"。比如 List&lt;?&gt; 可以容纳任何的类型。```public static void main(String args[]) {ArrayList<object> al = new ArrayList<object>();al.add("abc");test(al);}</object></object></object>

public static void test(ArrayList&lt;?&gt; al){
for(Object e: al){//no matter what type, it will be Object
System.out.println(e);
// in this method, because we don't know what type ? is, we can not add anything to al.
}
}

再次提醒:泛型是一个编译期的概念。在上述示例中,因为我们不知道 ? 所代表的具体类型,所以只能把其当作 Object 类型来对待。为了可以操作 ? 所代表的类型,我们应该考虑使用通配符。

List&lt; Object &gt; - List can contain Object or it's subtype

List&lt; ? extends Number &gt; -  List can contain Number or its subtypes.
List&lt; ? super Number &gt; - List can contain Number or its supertypes.

总结

我们发现 虽然 String 是 Object 的子类型,但是 ArrayList< String > 并不是 ArrayList< Object > 的字类型。但是,两个具有继承关系的泛型类型,当它们具有相同的类型参数时,它们之间也具有类似的基础关系。比如,ArrayList< String > 就是 Colleciton< String > 的子类型。

上述的泛型擦除技术适用于 Collection , 但不适用于Java的数组(array)。数组了解它的元素类型,并在运行时强制转换它的元素类型。这在Java中称为 具体化(reification)。比如 Object[] 就是 String[] 的父类。如果试图把一个 String 对象存储到一个 Integer[] 中, 在运行时会抛出来一个 ArrayStoreException 异常。

 


天天编码 , 版权所有丨本文标题:深入讲解Java的泛型擦除机制
转载请保留页面地址:http://www.tiantianbianma.com/java-generic-erasure.html/
喜欢 (3)
支付宝[多谢打赏]
分享 (0)
发表我的评论
取消评论

表情 贴图 加粗 删除线 居中 斜体 签到

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址
(1)个小伙伴在吐槽
  1. http://www.tiantianbianma.com/java-generic-erasure.html/ 中间的代码段出现了一些错误字符
    云天2018-07-19 15:37 回复 Windows 10 | Chrome 64.0.3282.140