2

在 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。因为对泛型类的类型没有任何假设,所以前面的异常不会发生。”

通配符有效而前一个无效,这对我来说仍然没有任何意义。如果我们必须在通配符示例中强制执行向上转换,为什么我们不能在第一个示例中也这样做呢?

如果有人能为我解决这个问题,我将不胜感激。

4

3 回答 3

1

通配符强迫你施放,所以你要知道真正的类。

第一种情况(如果可能的话)会给你一种错误的安全感并且没有警告,因为泛型的全部意义在于允许你在不经常转换的情况下工作。

于 2013-10-18T19:19:39.327 回答
0

泛型被设计为类型安全,以防您提供某种类型。但是由于类型擦除,您的泛型列表中究竟可以存储哪种类型的信息丢失了。这将具有与您仅提供类型相同的效果?。在运行时,不确定类型是否总是正确的,因此编译器会抱怨。

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

于 2013-10-18T19:37:27.633 回答
0

不允许第一个的实际原因是因为 java 的类型系统不健全。

规范说如果Sis-a T,那么S[]is-a 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 );
于 2013-10-18T20:12:13.943 回答