zoukankan      html  css  js  c++  java
  • 8.5 擦除和转换

    在严格的泛型代码中,带泛型声明的类总是应该带着类型参数。Java也允许在使用带泛型声明的类时不指定实际的类型。但如果没有为这个泛型类指定实际类型,此时被称为raw type(原始类型),默认是声明该泛型形参时指定的第一个上限类型。

    把一个具有泛型信息的对象赋给另一个没有泛型信息的变量时,所有尖括号之间的类型信息都被扔掉。比如一个List<String>类型被转换为List,该List对集合元素的类型检查变成了泛型参数的上限(即Object),下面程序示范了这种擦除。

     1 class Apple<T extends Number>
     2 {
     3     T size;
     4     public Apple()
     5     {}
     6     public Apple(T size)
     7     {
     8         this.size=size;
     9     }
    10     public void setSize(T size)
    11     {
    12         this.size=size;
    13     }
    14     public T getSize()
    15     {
    16         return this.size;
    17     }
    18 }
    19 
    20 public class ErasureTest
    21 {
    22     public static void main(String[] args)
    23     {
    24         Apple<Integer> a=new Apple<>(6);
    25         //a的getSize()方法返回Integer对象
    26         Integer as=a.getSize();
    27         //把a对象赋给Apple变量,失去尖括号里的类型信息
    28         Apple b=a;
    29         //b只知道size的类型为Number
    30         Number size1=b.getSize();
    31         //下面代码将引起错误
    32         Integer size2=b.getSize();//错误: 不兼容的类型: Number无法转换为Integer
    33     }
    34 }

     上面代码声明了一个带泛型声明的类Apple类,其泛型形参的上限为Number,这个泛型形参用来定义Apple的size变量。所以调用a.getSize()方法时返回Integer类型值。当把a变量赋值给一个不带泛型信息的b变量时,编译器就会丢失a对象的泛型信息,即尖括号里的信息都会丢失——因为Apple泛型形参的上限是Number类,所以编译器依然知道b的getSzie()方法返回Number类型,但具体是Number的哪个子剋就不清楚。

      从逻辑上看,List<String>类是List类的子类,如果直接把一个List对象赋给一个List<String>对象应该引起编译错误,但实际上不会。对于泛型而言,可以直接把一个List对象赋值给一个List<String>对象,编译器仅仅提示“未经检查的转换”,例如:

     1 import java.util.ArrayList;
     2 import java.util.List;
     3 public class ErasureTest2 
     4 {
     5     public static void main(String[] args) 
     6     {
     7         List<Integer> li=new ArrayList<>();
     8         li.add(6);
     9         li.add(9);
    10         System.out.println(li);//[6, 9]
    11         List list=li;//擦除
    12         //下面代码将引起警告“未经检查的转换”,编译、运行时完全正确
    13         List<String> ls=list;
    14 
    15         //但只要访问ls的元素,将引起运行时异常
    16         System.out.println(ls.get(0));
    17 //Exception in thread "main" java.lang.ClassCastException: class java.lang.Integer cannot be cast to class java.lang.String 
    18 //(java.lang.Integer and java.lang.String are in module java.base of loader 'bootstrap')
    19     }
    20 }

     上面程序中定义了一个List<Integer>对象,这个List<Integer>对象保留了元素的类型信息。当执行List list=li;时,编译器会丢失前者的泛型信息,即丢失list集合里的元素的类型信息,这就是典型的擦除。Java又允许直接把List对象赋给一个List<type>类型的变量,所以执行List<String> ls=list;编译可以通过,只是会发出警告:未经检查的转换。但对list变量实际上引用的是List<Integer>集合,所以试图把集合中的元素当成String类型的对象取出时,将会引发ClassCastException异常。 

  • 相关阅读:
    Android按钮事件的4种写法
    VB.NET转C#代码的工具
    C# FTP操作类
    Linq一对多联合查询
    软件工程师面试题(一)
    一道网传上海幼儿园升小学的数学题
    csdn博客刷点击率(java代码)
    .NET高端职位招聘要求
    csdn博客刷粉代码
    jQuery Ajax无刷新操作
  • 原文地址:https://www.cnblogs.com/weststar/p/12613412.html
Copyright © 2011-2022 走看看