在Java教程(http://docs.oracle.com/javase/tutorial/extra/generics/fineprint.html)中,我看到了以下内容:
// Not really allowed.
List<String>[] lsa = new List<String>[10];
Object o = lsa;
Object[] oa = (Object[]) o;
List<Integer> li = new ArrayList<Integer>();
li.add(new Integer(3));
// Unsound, but passes run time store check
oa[1] = li;
// Run-time error: ClassCastException.
String s = lsa[1].get(0);
If arrays of parameterized type were allowed, the previous example
would compile without any unchecked warnings, and yet fail at run-time
// OK, array of unbounded wildcard type.
List<?>[] lsa = new List<?>[10];
Object o = lsa;
Object[] oa = (Object[]) o;
List<Integer> li = new ArrayList<Integer>();
li.add(new Integer(3));
// Correct.
oa[1] = li;
// Run time error, but cast is explicit.
String s = (String) lsa[1].get(0);
然后他们解释说如果我们将List<String>[] lsa = new List<String>[10];
切换为
List<?>[] lsa = new List<?>[10];
然后它没关系,但我们必须向上倾斜。
我的一位教授问了下面这件事:“为什么后者会编译?”
然后他给出了答案:“当参数是什么时?意思是数组中的每个单元格都可以包含一个ArrayList。因为对泛型类的类型没有任何假设,以前的异常不会发生“。对于我来说,通配符的工作方式仍然没有意义,而前一个不能。如果我们必须在通配符示例中强制执行upcasting,为什么我们不能在第一个示例中执行此操作呢?
如果有人能为我解决这个问题,我会很感激。
答案 0 :(得分:1)
狂野卡片迫使你施展,所以由你来了解真正的班级。
第一种情况(如果可能的话)会给你一种虚假的安全感并且没有警告,因为仿制药的全部意义在于你可以在不经常投射的情况下工作。
答案 1 :(得分:0)
如果您提供某种类型,泛型被设计为类型安全的。但是由于类型擦除,丢失了确切地存储在通用列表中的哪种类型的信息。这与您只提供?
类型的效果相同。在运行时,它不确定类型是否总是正确的,因此编译器会抱怨。
两种变体中的数据都是相同的,但是一种变体编译,另一种则没有。这是因为在提供通配符时,您基本上会像开关一样关闭编译器的类型安全性,并告诉它您自己会关心它。如果它会失败,那将是你自己的错,而不是编译器的错误。 :)
答案 2 :(得分:0)
第一个被禁止的实际原因是因为java的类型系统不健全。
规范说如果S
是T
,那么S[]
就是T[]
。不幸的是,这个规则会导致类型问题,例如:
void unsoundness( Animal[] aanl ) {
// causes a runtime type check that the element types are compatible
aanl[ 0 ] = new Animal();
}
Dog[] adog = new Dog[ 1 ];
unsoundness( adog );
使用泛型和类型擦除时,运行时类型检查无法做出正确的判断。
void unsoundness( List< ? extends Animal >[] alstr ) {
alstr[ 0 ] = new ArrayList< Animal >();
}
List< Dog >[] alobj = new List< Dog >[ 1 ]; // fictitious
unsoundness( alobj );