4

假设有一个超类 America 及其两个子类 SouthAmerica 和 NorthAmerica

情况1

对于数组:

America[] am = new SouthAmerica[10]; //why no compiler error
am[0]= new NorthAmerica();    //ArrayStoreException at RunTime

案例2

在泛型中:

ArrayList<America> ame = new ArrayList<SouthAmerica>(); //this does not compile

我的问题不是为什么案例 2 不编译,而是我的问题是为什么案例 1 编译。我的意思是这个基本数组类型和子数组对象还能做什么?

4

4 回答 4

14

那是因为数组是协变的。

数组的这种行为在很大程度上被认为是一个错误:

String[] strings = new String[1];
Object[] objects = strings;
objects[0] = new Integer(1); // RUN-TIME FAILURE

通用集合 - 更新,修复了这个错误。

您可以使用有界通配符表示法<? super America>

ArrayList<? super America> = new ArrayList<SouthAmerica>();

这将允许您项目添加到列表中,但会避免出现问题的行为。

有关如何使用它们,请参阅此官方教程。

于 2013-06-29T19:47:50.970 回答
3

你做错了什么。根据您的描述,假设我们有以下内容

public class Sample {
    public static void main() {
    America am = new SouthAmerica[10];
    }
}
class America {
    private Integer Size;
}
class NorthAmerica extends America {
    private Integer USA;
}
class SouthAmerica extends America {
    private Integer Chile;
}

我尝试编译上面的类,但它出错了。

javac Sample.java. 
Sample.java:3: incompatible types
found   : SouthAmerica[]
required: America
America am = new SouthAmerica[10];
1 error
于 2013-06-29T20:02:44.650 回答
2

案例1:我假设您的意思是:

America[] am = new SouthAmerica[10]; //why no compiler error

当 SouthAmerica 扩展美国时,am 持有一系列 SouthAmerica 是有效的。

第二行无效,因为数组属于 SouthAmerica,而您正在尝试设置 NorthAmerica。SouthAmerica 不是 NorthAmerica 的超类。

第一个有效的要点是,稍后您可以有效地说:

am=new NorthAmerica[5];

这都是由于数组的协方差属性。

案例 2:虽然 SouthAmerica 确实扩展了美国,但这不适用于仿制药。ArrayList 不扩展 ArrayList,因为其含义不成立。泛型(即使在这种情况下它是一个 ArrayList)与完整数组的行为方式不同。

于 2013-06-29T19:49:07.603 回答
2

因为数组是协变的,而集合是逆变的。这意味着Stirng[]Object[],但List<String>不是List<Object>。您应该改写以下内容:

List<? extends America> list = new ArrayList<SouthAmerica>(); 
于 2013-06-29T19:49:50.763 回答