Java Generics WildCard Question: List<? extends

2019-01-04 02:38发布

Let's say I have these classes : Vehicle, Car and Spaceship:

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!");
    }

}

and I write this method addCars:

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

    }

Why do I get a compile time error?? I understand that List is a supertype of List for any X that extends Vehicle. right?

Thanks

Edit: the error I get (compile-time) : The method add(capture#2-of ? extends Vehicle) in the type List is not applicable for the arguments (Car).

10条回答
▲ chillily
2楼-- · 2019-01-04 02:40

Here's a pointer to why you're getting a compile error. Specifically,

List is an example of a bounded wildcard. The ? stands for an unknown type, just like the wildcards we saw earlier. However, in this case, we know that this unknown type is in fact a subtype of Shape. (Note: It could be Shape itself, or some subclass; it need not literally extend Shape.) We say that Shape is the upper bound of the wildcard.

There is, as usual, a price to be paid for the flexibility of using wildcards. That price is that it is now illegal to write into shapes in the body of the method. For instance, this is not allowed:

public void addRectangle(List<? extends Shape> shapes) {
     shapes.add(0, new Rectangle()); // Compile-time error! 
} 

You should be able to figure out why the code above is disallowed. The type of the second parameter to shapes.add() is ? extends Shape-- an unknown subtype of Shape. Since we don't know what type it is, we don't know if it is a supertype of Rectangle; it might or might not be such a supertype, so it isn't safe to pass a Rectangle there.

查看更多
Evening l夕情丶
3楼-- · 2019-01-04 02:40

Using prince get and put in wildcard If wildcard with Extends ---> Using get method If wildcard with Super ----> Using put method Here , you want to add value into List ( meaning put method) .You can change code

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());
    }
查看更多
爷、活的狠高调
4楼-- · 2019-01-04 02:41

You can either use:

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

(which means the caller is to pass a list of objects that are Vehicle or a super type)

or

private static void addCars(List<Vehicle> vcls)
查看更多
女痞
5楼-- · 2019-01-04 02:48

The supplied List is a list of some specific type of Vehicle (where, for the sake of argument we will refer to the type as T), but that specific type T is not known; it may be List<Vehicle>, List<Car>, etc. Therefore, since the specific generic type of the list is unknown, it is not permitted to invoke any method which requires the specific T as an argument. Only methods which don't involve T as an argument can be invoked.

The practical upshot of this, in the case of List, is that this prevents anything being added to the list - the list is not writable. On the other hand, the list can be read, but with the returned objects only known as Vehicle.

That is, the unknown type T cannot be supplied to the the List, but its known superclass of Vehicle can be returned by the list.

By way of example, given your method:

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

you could conceivably invoke:

List<Car> cars=new ArrayList<Car>();
addCars(cars);

which you intuit should be permitted. However, since addCars knows the list only as "some subtype of Vehicle", it can't be allowed to add objects to the list since the following invocation would then be just as valid:

List<Spaceship> ships=new ArrayList<Spaceship>();
addCars(ships);

whereby it becomes clear that it must be as mistake to try to add Car objects to a List under the guise of being a list of Vehicle objects.

查看更多
太酷不给撩
6楼-- · 2019-01-04 02:49

The type of parameter is ? extends Vehicle, which means an unknown subtype of Vehicle. Since we don’t know what type it is, we don’t know if it is a supertype of Car; it might or might not be such a supertype, so it isn’t safe to pass a Car there.

Read page 7 of this tutorial.

查看更多
我欲成王,谁敢阻挡
7楼-- · 2019-01-04 02:52

if following could be possible..

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

then you could call addCars in this way:

List<SpaceShip> ships = new ArrayList<SpaceShip>();
addCars(ships);
查看更多
登录 后发表回答