转换为泛型变量

Pet*_*neš 11 java generics casting

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

ArrayList<?> cislo = (ArrayList<? extends Number>) new ArrayList<Integer>();
Run Code Online (Sandbox Code Playgroud)

这可能不是最好的例子,但希望你能得到我的观点.这是如何运作的?它的演员类型是什么?

Hul*_*ulk 4

演员阵容是不必要的。

\n\n

作业

\n\n
ArrayList<?> list = new ArrayList<Integer>();\nArrayList<? extends Number> list2 = new ArrayList<Integer>();\n
Run Code Online (Sandbox Code Playgroud)\n\n

不需要任何显式转换。

\n\n

通配符类型是比具体类型“更通用”/“不太具体”的类型,并且上限通配符类型(例如? extends Number)比无界通配符类型?)更具体。

\n\n

有关通配符类型之间关系的更多信息,请参阅Oracle 通配符和子类型教程

\n\n

JLS 中指定这一点的相关部分是4.10.2。类和接口类型之间的子类型化

\n\n
\n

给定泛型类型声明 C (n > 0),参数化类型 C 的直接超类型(其中 Ti (1 \xe2\x89\xa4 i \xe2\x89\xa4 n) 是类型)均为以下类型:

\n\n
    \n
  • D,其中 D 是泛型类型,它是泛型类型 C 的直接超类型,\xce\xb8 是替换 [F1:=T1,...,Fn:=Tn]。
  • \n
  • C,其中 Si 包含 Ti (1 \xe2\x89\xa4 i \xe2\x89\xa4 n) (\xc2\xa74.5.1)。
  • \n
\n\n

[...]

\n
\n\n

指\n 4.5.1。参数化类型的类型参数

\n\n
\n

如果在以下规则的自反和传递闭包下,T2 表示的类型集可证明是 T1 表示的类型集的子集,则称类型参数 T1 包含另一个类型参数 T2,写作 T2 <= T1(其中 <: 表示子类型 (\xc2\xa74.10)):

\n\n
    \n
  • ?扩展 T <= ? 如果 T <: S 则扩展 S

  • \n
  • ?扩展 T <= ?

  • \n
\n\n

[...]

\n
\n\n

因此,根据这个定义,它是除原始类型之外的任何类型的超类型ArrayList<? extends Number>ArrayList<Integer>ArrayList<?>ArrayList<>

\n\n

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

\n\n
\n\n

如果您想分配不同类型的内容,则需要强制转换:

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

在该转换之后,您可以从列表中获取元素并将它们视为Numbers。如果您将其他内容分配给list引用而不是子类型,则转换将在运行时失败List<? extends Number>

\n\n
    Object list = new HashSet<Integer>();\n    List<? extends Number> numbers = (List<? extends Number>) list; //unchecked cast warning\n
Run Code Online (Sandbox Code Playgroud)\n\n

运行时失败抛出

\n\n

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

\n\n
\n\n

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

\n\n
List<String> stringList = new ArrayList<String>();\nstringList.add("hi");\nObject list = stringList;\nList<? extends Number> numbers = (List<? extends Number>) list; //unchecked cast warning, but (sadly) works\n\nNumber n = numbers.get(0); //fails: java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Number\n
Run Code Online (Sandbox Code Playgroud)\n\n

发生这种情况是因为在运行时,列表类型的擦除匹配。也可以看看有关擦除的教程

\n