转换为泛型变量

时间:2016-07-19 07:30:44

标签: java generics casting

我理解通用和铸造,但我不理解通用铸造。我以为我只能通过继承树向上或向下投射特定类型,但这证明我错了:

ArrayList<?> cislo = (ArrayList<? extends Number>) new ArrayList<Integer>();

这可能不是最好的例子,但希望你能明白我的意思。这是如何运作的?它的演员类型是什么类型?

1 个答案:

答案 0 :(得分:4)

演员阵容是不必要的。

作业

ArrayList<?> list = new ArrayList<Integer>();
ArrayList<? extends Number> list2 = new ArrayList<Integer>();

不需要任何明确的演员。

通配符类型比具体类型“更通用”/“更不具体”类型,upper bounded wildcard types(如? extends Number)比unbounded ones更具体(?

有关通配符类型之间关系的更多信息,请参阅Oracle Tutorial on Wildcards and Subtyping

JLS的相关部分指定为4.10.2. Subtyping among Class and Interface Types

  

给定泛型类型声明C(n> 0),参数化类型C的直接超类型,其中Ti(1≤i≤n)是一种类型,是以下所有:

     
      
  • D,其中D是泛型类型,它是泛型类型C的直接超类型,θ是替换[F1:= T1,...,Fn:= Tn]。
  •   
  • C,其中Si含有Ti(1≤i≤n)(§4.5.1)。
  •   
     

[...]

指的是 4.5.1. Type Arguments of Parameterized Types

  

类型参数T1被认为包含另一个类型参数T2,写为T2&lt; = T1,如果由T2表示的类型集合可证明是由T1表示的类型集合的子集,在反射和传递闭包下以下规则(其中&lt;:表示子类型(§4.10)):

     
      
  • ?延伸T <=?如果T&lt ;: S

  • ,则扩展S.   
  • ?扩展T&lt; =?

  •   
     

[...]

因此,通过此定义,ArrayList<? extends Number>ArrayList<Integer>的超类型,ArrayList<?>是除原始类型之外的任何ArrayList<>的超类型。

分配给超类型的变量不需要转换。

如果要分配不同类型的内容,则必须进行强制转换:

Object list = new ArrayList<Integer>();
//...somewhere else - the compiler does not know that list is always an ArrayList, but we tell it that we know what we are doing
List<? extends Number> numbers = (List<? extends Number>) list; //unchecked cast warning, but works

在演员之后,您可以例如从列表中获取元素并将其视为Number。如果您为list引用指定了不属于List<? extends Number>

的子类型的其他内容,则转换将在运行时失败
    Object list = new HashSet<Integer>();
    List<? extends Number> numbers = (List<? extends Number>) list; //unchecked cast warning

在运行时失败

java.lang.ClassCastException: java.util.HashSet cannot be cast to java.util.List

当泛型类型不匹配时,问题开始出现:

List<String> stringList = new ArrayList<String>();
stringList.add("hi");
Object list = stringList;
List<? extends Number> numbers = (List<? extends Number>) list; //unchecked cast warning, but (sadly) works

Number n = numbers.get(0); //fails: java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Number

这是因为在运行时,列表类型的擦除匹配。另请参阅the tutorial on erasure