【问题标题】:What's the differences between Array declaration and Collection declaration [duplicate]数组声明和集合声明有什么区别[重复]
【发布时间】:2014-06-26 04:31:26
【问题描述】:
 1.  List<Car> carList = new ArrayList<Sedan>();

 2.  List<Car> carList = new ArrayList<Car>();
    carList.add(new Sedan());

1 有编译错误,2 是合法的。

为什么变量声明的类型必须与我们传递给对象类型的类型匹配(不允许派生类型)? 我使用 Array 如下,这是绝对正确的:

int SIZE = 10;
Car[] carArray = new Sedan[SIZE];

谁能告诉我为什么集合必须声明为条件 2?谢谢

【问题讨论】:

  • @Takendarkk 我知道它是泛型,但泛型是在谈论使用尖括号作为类型,而不是关于超类和子类,不是吗?
  • @haifzhan 你真的认为超/子类与类型无关吗?
  • @Takendarkk 我不是说超类和子类与类型无关,我是在问你为什么它们与泛型有关,我期待答案
  • 数组实现被广泛认为是一个错误,幸好没有在 Collections 中重复

标签: java generics collections typesafe


【解决方案1】:

这个article和这个article详细解释一下。 Josh Bloch 使用泛型的 PECS 原则解释了主要思想

Producer Extends > Consumer Super  [PECS]

我主要取决于您作为生产者或消费者如何与存储在容器中的数据进行交互。

另一个问题是何时检查类型安全、运行时间或编译时间。考虑以下几点:

// array type safety errors caught at run time
Object[] objArray = new Long[3];
objArray[0] = "i'm a string";
Object notANumber = objArray[0];

// run time exception
Long number = (Long)notANumber;

// generic type errors caught at compile time
// use pecs principle in new ArrayList<...>();
List<Number> list = new ArrayList<Number>();
list.add("not a number"); // compile time error
list.add(Long.valueOf(42L));

Long wontWork = list.get(0);  // compile time error
Number works = list.get(0); 

【讨论】:

    【解决方案2】:

    这样编译:

    List<? extends Car> carList = new ArrayList<Sedan>();
    

    但它不会像你期望的那样运行,如果你对泛型没有足够的理解,结果可能会在后面产生混淆。您真的应该阅读教程,其中有很多。

    【讨论】:

      【解决方案3】:

      它是关于泛型中的类型安全的。假设没问题:

      List<Dog> dogs = new ArrayList<Dog>();
      List<Animal> animals = dogs;
      animals.add(new Cat());
      

      你当然可以在 Animal 类型的列表中添加一个新的 cat 对象,但是如果动物指的是狗,你会把一只猫和一堆狗搞砸,这是非常危险的,为了避免这种情况,输入安全泛型只允许声明类型匹配对象类型。

      【讨论】:

        【解决方案4】:

        Sedan[]Car[] 的子类型。但这对类型安全有非常负面的影响,因为下面的代码是合法的:

        Sedan[] sedans = new Sedan[10];
        Car[] cars = sedans; // legal, since Sedan[] extends Car[]
        cars[0] = new Car(); // Houston, we have a problem
        

        此代码在运行时会导致 ArrayStoreException,因为应该只包含轿车的数组将包含非轿车。

        泛型的目标是拥有类型安全的集合。因此决定设计它们,以便在编译时而不是运行时检测到上述问题。集合比数组更常用,让它们类型安全是件好事。

        所以他们决定List&lt;Sedan&gt; 不是List&lt;Car&gt;

        【讨论】:

          【解决方案5】:

          在您的案例 1 中,您实际上要做的是创建一个 ArrayList 来保存各种汽车对象,然后尝试将此变量分配给轿车的 ArrayList。这在本质上是行不通的,因为您是从大到小(轿车是轿车,但轿车可能不是轿车)。

          基本上,您在案例 1 中的 carList 将无法工作,因为使用泛型,任何 Car 都应该能够放入 carList。这意味着我可以在添加轿车后立即致电carList.add(new Compact();

          案例 2 遵循此约定。

          我喜欢在使用泛型时考虑它的方式是,在案例 1 中,您实际上是在创建两种不同类型的对象的实例。想象一下 ArrayListCarArrayListSedan,如果你愿意的话。每个人都专门接受他们的具体论点。令人困惑,我知道,因为数组可以工作,但这就是它的设计方式。

          【讨论】:

            猜你喜欢
            • 2016-02-04
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2010-11-27
            相关资源
            最近更新 更多