0

我对Java(和英语)很陌生,所以请多多包涵。

试图写出类似...

Container con = new Container<Book>();
con.insert(new Book());
con.insert(new Car());

...并且没有收到任何类型的错误。但是像...这样的线条

Car c = con.remove(); // removes the last inserted element for simplicity

说“错误:不兼容的类型”,所以我把它改成了

Object carObj = (Car) con.remove();

它奏效了。我的问题是:当我说

new Container<Book>();

我创建了一个只能容纳 Book 类型对象的容器,但是由于指针(它是非泛型的?)我可以突然将任何类型的对象放入我的容器中。这里发生了什么?指针仅在容器中的任何内容中看到对象个性,但我不知道指针允许容器中的每个具有对象个性的对象主要创建为通用(我的公式可能是错误的)。所以当我有一个非泛型指针时,我是创建一个泛型容器还是非泛型容器都没有关系?它总是被认为是一个非通用容器(当我删除它们时我必须在其中投射对象)?

new Container<Book>().insert(new Car()); // compiler error as excepted

好奇并使问题变得更糟(也许)。

Container<Car> cars = new Container();
cars.insert(new Book()); // compiler error: required Car, found Book

现在指针只看到容器中的汽车个性。但是即使我将容器创建为非通用容器,它也不允许我放入一本书。为什么?

new Container().insert(new Car()); // works fine

不得不说,既迷人又刺激……

4

3 回答 3

1

您的容器是原始容器,而不是通用容器。它被声明为Container. 它应该被声明为Container<Book>.

完成后,线

con.insert(new Car());

不会再编译了。

在 Java 中,对象的泛型类型只是编译时的东西。在运行时,由于擦除,它只是一个容器。因此,如果您不将容器声明为Container<Book>Container,您将拥有一个原始 Container 并且编译器不会检查您存储在其中的对象类型的任何内容。

为了更清楚(至少我希望如此),这条线

Container con = new Container<Book>();

相当于

Container con = (Container) (new Container<Book>());

它将对 aContainer<Book>的引用转换为对原始 Container 的引用,破坏了它的类型安全性。

于 2013-02-02T17:17:08.993 回答
1

您正在对引用进行操作:引用的类型将在编译时使用。将 aBook插入 aContainer<Car>显然是错误的,就像将 aBook或 aCar插入 a没有任何问题一样Container

同样,当引用完全不正确时,期望 aContainer.remove返回 a是不正确的,因为没有理由期望返回的对象是 a ——它可能是 a或 fish。Car<Container>CarBook

于 2013-02-02T17:11:50.707 回答
0

在已经有很多没有泛型编写的代码之后,Java 添加了泛型。泛型的设计者希望将标准库容器更改List为 into List<X>,但已经编写了很多代码List,如果他们要求所有用途都成为用途,那么这些代码将不再编译List<X>。此外,他们希望人们使用他们自己的遗留库,例如,要求 aList并希望它只包含String能够传入 a 的实例List<String>

他们处理这个问题的方法是为每个泛型类型引入“原始类型”的概念,这基本上只是通过不在泛型类型之后写尖括号而获得的类型(例如List,而不是List<String>)。原始类型与它们的非原始等价物有不同的类型检查规则;例如,如果您有 a那么它对任何进入它List都是合法的,但是当您返回某些东西时,它会以您需要向下转换的形式返回,而 a只会允许您进入a ,但作为回报,您不需要向下转换' s 结果得到了回报。addObjectgetObjectList<String>addStringgetString

不幸的是,由于语言设计者制定的向后兼容规则,他们允许您编写类似的表达式

List rawList = new ArrayList<String>();
rawList.add(new PeanutButterSandwich());

没有编译时错误。你甚至可以做更糟糕的事情,比如

List<String> stringList = new ArrayList<String>();
stringList.add("string");
List rawList = stringList;
List<PeanutButterSandwich> sandwichList = (List<PeanutButterSandwich>) rawList;
PeanutButterSandwich sandwich = sandwichList.get(0);

编译(带有关于未经检查的转换的警告,这意味着您从原始类型转换为泛型类型,但编译器不知道它是合法的)。当然,这段代码肯定会在运行时引发异常,因为位置 0 的元素是 a String,而不是 a PeanutButterSandwich

重要的是要记住原始类型只是为了向后兼容,你不应该在新代码中使用它们。此外,如果您曾经处理原始类型,在将它们转换为泛型类型时要非常小心,因为编译器无法阻止您做错事。

于 2013-02-02T19:28:03.020 回答