Java泛型通配符问题:List<;?扩展A>;

Java泛型通配符问题:List<;?扩展A>;,java,generics,wildcard,Java,Generics,Wildcard,假设我有以下几类:交通工具、汽车和宇宙飞船: class Vehicle{ void rideVehicle(Vehicle v){ System.out.println("I am riding a vehicle!"); } } class Car extends Vehicle{ void rideVehicle(Vehicle c){ System.out.println("I am riding a car!");

假设我有以下几类:交通工具、汽车和宇宙飞船:

class Vehicle{

    void rideVehicle(Vehicle v){
        System.out.println("I am riding a vehicle!");
    }

}

class Car extends Vehicle{
    void rideVehicle(Vehicle c){
        System.out.println("I am riding a car!");
    }
}


class SpaceShip extends Vehicle{
    void rideVehicle(Vehicle c){
        System.out.println("I am riding a spaceship!");
    }

}
我写了这个方法:

private static void addCars(List<? extends Vehicle> vcls){
        vcls.add(new Car());
        vcls.add(new Car());
        vcls.add(new Car());

    }

私家车(列表方法参数在子类型中是逆变的,根据通配符的定义,对于扩展
Vehicle
Foo
的每种类型
T
都是
Foo
的子类型。这意味着,当您只关心返回类型,但在这种情况下不起作用时,通配符非常有用n要将类型的值传递给方法

问题是用户可能会尝试调用

List<SpaceShip> l = ...
addCars(l);
列表l=。。。
addCars(l);

如果你的代码要编译,
l
将是一个包含3辆汽车的宇宙飞船列表。显然不好。

方法参数在子类型中是逆变的,根据通配符的定义,对于扩展
车辆的每种类型
T
Foo
都是
Foo
的子类型如果只关心返回类型,则通配符非常有用,但在这种情况下,如果要将该类型的值传递给方法,则通配符不起作用

问题是用户可能会尝试调用

List<SpaceShip> l = ...
addCars(l);
列表l=。。。
addCars(l);

如果要编译代码,
l
将是一个包含3辆汽车的宇宙飞船列表。显然不好。

参数类型是
?extensed Vehicle
,这意味着一个未知的子类型 因为我们不知道它是什么类型,所以我们不知道它是否是超类型 属于
汽车的
;它可能是也可能不是这样的超型,所以通过一辆汽车是不安全的
汽车
在那里


阅读。

的第7页,参数类型为
?扩展车辆
,表示未知的子类型 因为我们不知道它是什么类型,所以我们不知道它是否是超类型 属于
汽车的
;它可能是也可能不是这样的超型,所以通过一辆汽车是不安全的
汽车
在那里

当您说
私有静态无效添加车(列表
私有静态无效添加车(列表您可以使用:

private static void addCars(List<? super Vehicle> vcls)
private static void addCars(列表您可以使用:

private static void addCars(List<? super Vehicle> vcls)
private static void addCars(List指向编译错误原因的指针。具体来说

列表就是一个例子 有界通配符。表示 未知类型,就像 我们前面看到的通配符 这种情况下,我们知道这是未知的 类型实际上是形状的一个子类型。 (注意:它可以是形状本身,或者 一些子类;它不需要逐字逐句 扩展形状。)我们说形状是 通配符的上限

像往常一样,我们要付出代价 为了使用的灵活性 通配符。价格就是这样 现在在中写入形状是非法的 方法的主体。例如, 这是不允许的:

public void addRectangle(List指向编译错误原因的指针。具体来说

列表就是一个例子 有界通配符。表示 未知类型,就像 我们前面看到的通配符 这种情况下,我们知道这是未知的 类型实际上是形状的一个子类型。 (注意:它可以是形状本身,或者 一些子类;它不需要逐字逐句 扩展形状。)我们说形状是 通配符的上限

像往常一样,我们要付出代价 为了使用的灵活性 通配符。价格就是这样 现在在中写入形状是非法的 方法的主体。例如, 这是不允许的:


public void addRectangle(列表提供的列表是一些特定类型车辆的列表(其中,为了便于论证,我们将该类型称为
T
),但该特定类型
T
未知;它可能是
List
List
,等等。因此,由于列表的特定泛型类型未知,因此不允许调用任何需要特定
T
作为参数的方法。只有不涉及
T
作为参数的方法才可以inv好的

在列表的情况下,实际的结果是,这会阻止向列表中添加任何内容-列表不可写。另一方面,列表可以读取,但返回的对象仅称为
车辆

也就是说,无法将未知类型
T
提供给列表,但列表可以返回其已知超类
Vehicle

举个例子,给出您的方法:

private static void addCars(List<? extends Vehicle> vcls) {

因此,很明显,试图以
车辆
对象列表的名义将车辆对象添加到列表中肯定是错误的。

所提供的列表是某种特定类型车辆的列表(为了便于论证,我们将该类型称为
T
),但该特定类型
T
未知;它可能是
List
List
,等等。因此,由于列表的特定泛型类型未知,因此不允许调用任何需要特定
T
作为参数的方法。只有不涉及
T
作为参数的方法才可以inv好的

在列表的情况下,实际的结果是,这会阻止向列表中添加任何内容-列表不可写。另一方面,列表可以读取,但返回的对象仅称为
车辆

也就是说,无法将未知类型
T
提供给列表,但列表可以返回其已知超类
Vehicle

举个例子,给出您的方法:

private static void addCars(List<? extends Vehicle> vcls) {
因此,很明显,试图以
车辆
对象列表的名义将车辆对象添加到列表中肯定是错误的
private static void addCars(List<? extends Vehicle> vcls) {
List<Car> cars=new ArrayList<Car>();
addCars(cars);
List<Spaceship> ships=new ArrayList<Spaceship>();
addCars(ships);
private static void addCars(List<? extends Vehicle> vcls){
        vcls.add(new Car());
        vcls.add(new Car());
        vcls.add(new Car());
    }
List<SpaceShip> ships = new ArrayList<SpaceShip>();
addCars(ships);
private static void addCars(List<? super Car> vcls){
    vcls.add(new Car());
    vcls.add(new Car());
    vcls.add(new Car());
List<? extends Vehicle become List<? super Vehicle> then it will compile legally
private static void addCars(List<? super Vehicle> vcls){
        vcls.add(new Car());
        vcls.add(new Car());
        vcls.add(new Car());
    }