Array声明和Collection声明之间的区别是什么

时间:2014-05-08 16:36:48

标签: java generics collections typesafe

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

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

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

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

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

有谁能告诉我为什么收藏品必须声明为条件2?感谢

5 个答案:

答案 0 :(得分:5)

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<Sedan>不是List<Car>

答案 1 :(得分:1)

在你的案例1中,你实际上在做的是创建一个ArrayList来保存各种汽车对象,然后尝试为这个变量分配一个ArrayList轿车。这不会起作用,因为你要从大到小(轿车是轿车,但轿车可能不是轿车)。

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

案例2遵循这一惯例。

我喜欢在使用泛型时考虑它的方式是你在案例1中基本上创建了两种不同类型对象的实例。想象一下ArrayListCarArrayListSedan片刻,如果你愿意的话。每个人都专门采取他们的具体论点。令人困惑,我知道,因为数组会起作用,但这只是它的设计方式。

答案 2 :(得分:1)

关于Generics的类型安全。假设没关系:

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

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

答案 3 :(得分: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); 

答案 4 :(得分:0)

编译:

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

但它不会像你期望的那样表现,如果你对泛型不够了解,结果可能会在以后混淆。你应该真正阅读一个教程,其中有很多。