为什么Java中允许使用未知泛型类型的数组?

时间:2013-10-18 19:13:22

标签: java generics

在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,为什么我们不能在第一个示例中执行此操作呢?

如果有人能为我解决这个问题,我会很感激。

3 个答案:

答案 0 :(得分:1)

狂野卡片迫使你施展,所以由你来了解真正的班级。

第一种情况(如果可能的话)会给你一种虚假的安全感并且没有警告,因为仿制药的全部意义在于你可以在不经常投射的情况下工作。

答案 1 :(得分:0)

如果您提供某种类型,泛型被设计为类型安全的。但是由于类型擦除,丢失了确切地存储在通用列表中的哪种类型的信息。这与您只提供?类型的效果相同。在运行时,它不确定类型是否总是正确的,因此编译器会抱怨。

两种变体中的数据都是相同的,但是一种变体编译,另一种则没有。这是因为在提供通配符时,您基本上会像开关一样关闭编译器的类型安全性,并告诉它您自己会关心它。如果它会失败,那将是你自己的错,而不是编译器的错误。 :)

答案 2 :(得分:0)

第一个被禁止的实际原因是因为java的类型系统不健全。

规范说如果ST,那么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 );