Java:指向泛型对象的非泛型指针的含义



我对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类型对象的容器,但由于指针(这是非通用的?),我可以突然将任何类型的对象放在我的容器中。这里发生了什么?指针只在容器中的任何内容中看到Object个性,但我不知道指针允许容器中的每个对象都具有Object个性,该容器主要创建为泛型(我的公式可能是错误的)。所以,当我有一个非泛型指针时,我创建的是泛型容器还是非泛型容器都无关紧要?它总是被认为是一个非通用容器(当我删除对象时,我必须强制转换对象)?

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

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

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

不得不说,它既迷人又令人恼火。。。

您正在对引用进行操作:引用的类型将在编译时使用。将Book插入Container<Car>显然是错误的,就像将BookCar插入Container没有错一样。

类似地,当引用只是<Container>时,期望Container.remove返回Car是不正确的,因为没有理由期望返回的对象是Car–它可能是CCD_ 10或鱼。

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

一旦完成,线路

con.insert(new Car());

将不再编译。

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

为了更清楚(至少我希望如此),行

Container con = new Container<Book>();

相当于

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

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

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

他们处理这一问题的方法是为每个泛型类型引入"原始类型"的概念,这基本上就是你不在泛型类型后面写尖括号得到的类型(例如List而不是List<String>)。原始类型与非原始类型具有不同的类型检查规则;例如,如果你有一个List,那么add和任何Object都是合法的,但当你返回某个get时,它会返回为你需要下变频的Object,而List<String>只允许你返回addString,但作为回报,你不需要下变频get的结果就可以返回String

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

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中的元素是String,而不是PeanutButterSandwich

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

相关内容

  • 没有找到相关文章

最新更新