【问题标题】:Java Arrays vs GenericsJava 数组与泛型
【发布时间】:2013-06-27 08:53:51
【问题描述】:

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

案例一

对于数组:

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 编译。我的意思是这个基本数组类型和子数组对象还能做什么?

【问题讨论】:

标签: java generics reflection collections


【解决方案1】:

那是因为数组是covariant

数组的这种行为在很大程度上被认为是mistake:

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

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

您可以使用有界通配符符号&lt;? super America&gt;

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

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

请参阅this official tutorial 了解如何使用它们。

【讨论】:

  • 是Sun为了像Arrays.sort(any_array)这样的方法而犯的错误??????
  • @SachinVerma Java 并不总是有泛型。在没有泛型的情况下不允许数组协方差会使一些任务变得非常乏味。您的Arrays.sort 示例是一个很好的示例,说明没有数组协方差或泛型会出现的问题。现在,我们有了泛型,在许多人看来,这种行为弊大于利。
  • 我不会称之为错误;数组是协变的,而支持泛型的类不是向后兼容的结果;这解释了为什么您在列表上有一个专用的.toArray() 方法,以便在运行时需要一个“类型安全”的数组。
  • @fge 当我写错误时,我的意思是回想起来是错误的。我相信如果 Gosling 在构建 Java 时考虑了泛型,就不会发生数组协变。在他的位置上,设计一种没有泛型的语言——这似乎是合理的行为。在我之前对 OP 的评论中,我讨论了为什么协方差在没有泛型的语言中很不错。这就是为什么其他语言(如 C#)紧随其后,非常清楚问题的本质,以及它解决的问题。
  • @BenjaminGruenbaum 好吧,.NET 语言有机会从 Java 的错误中吸取教训;)但更广泛地说,Java 语言设计者在某些时候必须打破向后兼容性;如果做不到这一点,那么在未来某个时候推广 Java 将变得不可持续。
【解决方案2】:

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

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

【讨论】:

  • 我只是指 OPs 声明,它提到它会编译但它不会。
【解决方案3】:

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

List<? extends America> list = new ArrayList<SouthAmerica>(); 

【讨论】:

    【解决方案4】:

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

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

    当 SouthAmerica 扩展 America 时,am 持有 SouthAmerica 数组是有效的。

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

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

    am=new NorthAmerica[5];
    

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

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

    【讨论】:

      猜你喜欢
      • 2017-08-21
      • 1970-01-01
      • 2011-05-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-06-13
      • 1970-01-01
      • 2011-12-24
      相关资源
      最近更新 更多