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());
}