1

So the function below is supposed to be a function that takes a Car object and adds it to a Col<> object.

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

The question asked whether if adding a variable n of type Nissan object to a variable c of type List<Car> would work (ie. insertCar(c, n))

The answer is yes but I'm not sure why. I thought adding subtypes of an object Car would not be possible because of the use of super. That it would only take types of type Car or any supertype of Car.

Anyone able to me understand?

EDIT Is it that...

I wouldn't be able to add a Nissan if the List<> itself was of some other subtype being passed in? For example, if List<? super Car> was actually List<? super Ford>

There seems to be conflicting answers below but this is a question provided for exam review so pretty sure the question and answer provided are correct. It's just my understanding of it is what I'm not sure about.

4

3 回答 3

1

问题询问是否将类型变量添加n到类型Nissan变量cList<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 {}

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

  1. 's 的List<Car>第一个参数是有效的吗?的,它是一个子类型,例如见这里。insertCarList<? super Car>
  2. 's 的Nissan第二个参数是有效的吗?的,它是一个子类型。insertCarCar
  3. 通话c.add(x)有效吗?的,参数x必须是由 定义的类型Car或超类型,Car定义List<? super Car> c也是如此Car x

那么为什么会让人困惑呢?因为您将类型传递给第二个参数Nissan,并认为现在第 3 点将中断,因为x它不是类型Car或超类型Car(它是子类型)。发生的事情Nissan是被向上转换为 a Car,这是一个可行的论点。

请记住,要知道调用c.add(x)是否有效,您所要做的就是查看cand的定义x(在方法的参数列表中)。这确保只要使用有效参数调用该方法,该调用c.add(x)就有效。此检查与调用时的(两个)类型检查无关insertCar。这些是我们在上面执行的 3 项检查。

编辑: 那么为什么不起作用insertCar(List<? super Nissan> c, Car x)

因为类型擦除。在编译期间,编译器会删除所有类型参数,并用其第一个边界替换每个类型参数(参见此处)。你得到的是对List<Nissan>to的请求add(Car)。但这无法编译,因为Car它不是Nissan.

在第一种情况下List<? 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,这与方法的内容无关。

于 2015-12-15T23:38:32.463 回答
0

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

于 2015-12-15T23:21:27.133 回答
0

答案是肯定的,但我不知道为什么。我认为添加对象 Car 的子类型是不可能的,因为使用了 super。它只需要 Car 类型或 Car 的任何超类型。

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

于 2015-12-15T23:10:09.490 回答