被Javagenerics混淆需要强制转换

我对以下代码感到困惑:

import java.util.ArrayList; import java.util.LinkedList; import java.util.List; public class GenericsTest { public void foo() { T var = (T) new LinkedList(); } public static void main(String[] args) { GenericsTest gt1 = new GenericsTest(); gt1.foo(); System.out.println("Done"); } } 

无论我传递给构造函数的Type参数如何, T的运行时类型似乎都是java.util.List

那么为什么编译器在分配var时需要转换为T ? 它不应该在编译时知道LinkedList可以分配给List吗?

我理解代码是假的,我理解为什么它在运行时工作,即使它看起来不应该。 令我困惑的部分是为什么编译器要求我在进行赋值时键入(T)? 然而,如果没有伪造的话,它就可以很好地编译。

据推测,编译器理解擦除。 看起来编译器应该能够在没有强制转换的情况下编译代码。

海报在评论中问道,

但是,大概是编译器知道它为什么需要将转换为(T)。 演员有没有可能失败的方法?

这个演员阵容不会失败。 但编译器警告说, 这段代码会设置一个时间炸弹,以便在ClassCastException 其他地方爆炸。

在该示例中,没有理由使用generics,因为API都不使用类型变量T 看一下更真实的generics应用。

  public class GenericsTest { 3 public T foo() { 4 T var = (T) new LinkedList(); 5 return var; 6 } 8 public static void main(String... argv) { 9 GenericsTest gt1 = new GenericsTest(); 10 gt1.foo(); 11 System.out.println("Test one okay"); 12 ArrayList list = gt1.foo(); 13 System.out.println("Test two okay"); 14 } } 

在第12行ClassCastException ,没有强制转换? 调用代码完全正确。 无效的强制转换(bug)位于调用方法的第4行。 但是这个例外是在某个时间和地点提出的。

Javagenerics的目的是确保代码是类型安全的。 如果所有代码都是在没有“未选中”警告的情况下编译的,那么保证在运行时不会引发ClassCastException 。 但是,如果您所依赖的库写得不正确,就像这个例子一样,承诺就会被破坏。

LinkedList可分配给List ,但可能无法分配给T

在某些方面,您的测试代码不应该工作 – 它只能起作用,因为编译器有效地删除了强制转换,因为它在执行时没用(由于类型擦除)。 它在编译时非常有用,因为它要求您(开发人员)向编译器承诺您正在执行无法检查的有效内容。 碰巧,你正在做的事情无效的,但是编译器无法知道这一点,并且在没有更多信息的情况下无法在执行时检查它。 您可以提供以下信息:

 import java.util.ArrayList; import java.util.LinkedList; import java.util.List; public class GenericsTest { Class clazz; public GenericsTest(Class clazz) { this.clazz = clazz; } public void foo() { T var = clazz.cast(new LinkedList()); } public static void main(String[] args) { GenericsTest gt1 = new GenericsTest(ArrayList.class); gt1.foo(); System.out.println("Done"); } } 

现在这将失败并出现相应的exception – 类型信息在执行时仍然可用,我们正在使用它以安全的方式执行转换。

请注意,如果使用适当的警告进行编译,编译器将告诉您原始代码实际上并未检查任何内容。

有关此主题和许多其他主题的更多信息,请查看相当全面的Javagenerics常见问题解答 。

那是因为类型擦除 ; 在编译时,generics参数变为其下限。

编译器试图告诉你出了问题。 如果它做了你认为它应该做的事情,你会得到一个ClassCastException – 你不能将LinkedList转换为ArrayList

我以为你是来自C#? 在这种情况下,Javagenerics不是C#generics。

当您提供generics类型参数时,Java不会生成强类型类,它只使用最小公用命名类型,该类型可用于可提供的所有可能的generics类型参数组合。

因此,在这种情况下,由于您指定了extends List ,因此使用extends List