我对以下代码感到困惑:
import java.util.ArrayList; import java.util.LinkedList; import java.util.List; public class GenericsTest<T extends List> { public void foo() { T var = (T) new LinkedList(); } public static void main(String[] args) { GenericsTest<ArrayList> gt1 = new GenericsTest<ArrayList>(); gt1.foo(); System.out.println("Done"); } }
无论我传递给构造函数的Type参数是什么,T的运行时类型似乎都是java.util.List.
那么为什么编译器在分配var时需要转换为T?它不应该在编译时知道LinkedList可以分配给List吗?
我理解代码是假的,我理解为什么它在运行时工作,即使它看起来不应该.令我困惑的部分是为什么编译器要求我在进行赋值时键入(T)?然而,如果没有伪造的话,它可以很好地编译.
据推测,编译器理解擦除.看起来编译器应该能够在没有强制转换的情况下编译代码.
解决方法
海报在评论中问道,
However,presumably the compiler knows
that so why does it need to have the
cast to (T). Is there any possible way
the cast could ever fail?
这个演员阵容不会失败.但编译器警告说,这段代码会设置一个时间炸弹,以便在ClassCastException的其他地方爆炸.
在该示例中,没有理由使用泛型,因为API都没有使用类型变量T.请查看更真实的泛型应用程序.
public class GenericsTest<T extends List> { 3 public T foo() { 4 T var = (T) new LinkedList(); 5 return var; 6 } 8 public static void main(String... argv) { 9 GenericsTest<ArrayList> gt1 = new GenericsTest<ArrayList>(); 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 .ClassCastException,没有强制转换?调用代码完全正确.无效的强制转换(bug)位于调用方法的第4行.但是这个例外是在某个时间和地点提出的.
Java泛型的目的是确保代码是类型安全的.如果所有代码都是在没有“未选中”警告的情况下编译的,那么保证在运行时不会引发ClassCastException.但是,如果您所依赖的库写得不正确,就像这个例子一样,承诺就会被破坏.