使用super的方法可以获取对象的子类型并将其添加到列表中吗?

时间:2015-12-15 23:06:31

标签: java generics subtyping

因此,下面的函数应该是一个带有Car对象并将其添加到Col<>对象的函数。

void insertCar(List<? super Car> c, Car x) {
   c.add(x)
}

问题是,是否将类型为n的变量Nissan的变量c添加到类型为List<Car>的变量insertCar(c, n)中(即。Car

答案是肯定的,但我不确定原因。我认为由于super的使用,无法添加对象Car的子类型。它只需要Car类型或List<>的任何超类型。

任何能让我理解的人吗?

编辑是......

如果List<? super Car>本身属于某个其他子类型,我将无法添加日产?例如,如果List<? super Ford>实际上是var housecontroller = require("./controllers/housecontroller"); ...

以下似乎存在相互矛盾的答案,但这是一个为考试复习提供的问题,因此请确保提供的问题和答案是正确的。只是我对它的理解是我不确定的。

3 个答案:

答案 0 :(得分:1)

  

问题是,是否将类型为n的变量Nissan的变量c添加到类型为List<Car>的变量insertCar(c, n)中(即。public class GenericCheck { static void insertCar(List<? super Car> c, Car x) { c.add(x); } public static void main(String[] args) { List<Car> c = new ArrayList<>(); Nissan n = new Nissan(); insertCar(c, n); } } class Car {} class Nissan extends Car {}

要将您的文字写入代码,我相信这就是您所说的:

List<Car>

是。这很好,但需要进行3种类型的检查:

  1. insertCar List<? super Car> Nissan的有效第一个参数是insertCar吗? ,它是一个子类型,例如,请参阅here
  2. Car c.add(x) x的有效第二个参数是Car吗? ,这是一个子类型。
  3. 来电Car有效吗? ,参数List<? super Car> c必须是Car x类型或Nissan定义的超类型x,定义是这样的Car
  4. 那为什么会让人困惑?因为您传递给第二个参数Car类型,而认为现在点3将会中断,因为Nissan不属于Car类型或超类型c.add(x)(这是一个子类型)。会发生的事情是c被提升为x,这是一个可行的论据。

    请记住,要知道调用c.add(x)是否有效,您所要做的就是查看insertCarinsertCar(List<? super Nissan> c, Car x)的定义(在方法的参数列表中)。这可确保只要使用有效参数调用方法,调用List<Nissan>就有效。在调用add(Car)时,此检查与(两个)类型检查无关。这是我们上面进行的3次检查。

    修改:为什么Car不起作用?

    因为类型擦除。在编译期间,编译器会擦除所有类型参数,并用其第一个边界替换每个参数(请参阅here)。您得到的是NissanList<? super Car>的请求。但这无法编译,因为List<Car>不是add(Car)的子类型。

    static void insertCar(List<? super Car /* or Nissan */> c, Car x) { c.add(x); } 的第一种情况下,键入删除会导致insertCar(..., Car),然后insertCar(..., Nissan)有效。

    我认为,最清楚你的困惑是认识到泛型提供仅编译时检查。正如我在上面提到的代码块

    c.add(x)
    无论在运行时中调用该方法的参数是什么,都必须编译

    。这意味着第一个方法参数中的泛型与传递给第二个参数的类型无关:Car==不会影响return "";的可编译性。给定的参数被转换(upcasted)到方法的参数类型"",这与方法的内容无关。

答案 1 :(得分:0)

  

答案是肯定的,但我不确定原因。我想加入了亚型   因为超级的使用,汽车是不可能的。那   它只会采用Car类型或Car的任何超类型。

任何超类引用都可以保存其实例的对象或其任何子类实例,因此这是完全合法的。

答案 2 :(得分:0)

您的子类型objet将至少具有Car对象中的所有属性和方法,通常还有更多自己的方法。如果将Nissan对象分配给Car变量,则可以调用Car变量的所有方法。相反,将Car实例分配给Nissan对象是不可能的,因为Nissan对象可能有比Car实例更多的方法。