3

I have the code below. It seems that I can't put an object of class Nonlife that is a superclass of class Vehicle into a container of type Collection<? super Vehicle> ALTHOUGH there is a keyword "super" in the wildcard type, and only objects of class Vehicle and SUV that is a subclass of class Vehicle are feasible. Could someone give me some advice?

public class SUV extends Vehicle

public class Vehicle extends Nonlife implements Externalizable

public class Nonlife extends Thing

public class Thing implements Comparable<Thing>, Serializable

public class SupperWildcardTest20200830 {
    
    public static void main(String[] args) {
        Collection<Thing> coll = new ArrayList<>();
        appendVehicle2Collection(coll);
        appendSuv2Collection(coll);
        for (Thing el: coll) {
            System.out.println("" + el);
        }
    }
    
    public static void appendVehicle2Collection(Collection<? super Vehicle> coll) {
        coll.add(new Vehicle());
    }
    
    public static void appendSuv2Collection(Collection<? super Vehicle> coll) {
        coll.add(new SUV());
    }
    
    public static void appendNolife2Collection(Collection<? super Vehicle> coll) {
        /**
         * incompatible types: Nonlife cannot be converted to CAP#1
         *  where CAP#1 is a fresh type-variable:
         *    CAP#1 extends Object super: Vehicle from capture of ? super Vehicle
         */
        coll.add(new Nonlife());
    }
}
cmpltrtok
  • 99
  • 5
  • reading this might be of use : https://stackoverflow.com/questions/4343202/difference-between-super-t-and-extends-t-in-java – Steph Aug 30 '20 at 09:06

2 Answers2

2

The only thing you know for sure about Collection<? super Vehicle> is that it is a collection of Vehicles, or a collection of a supertype of Vehicles. So the only thing you know for sure that you can put into this collection are Vehicles. So you are allowed to pass a Collection of NonLifes to the method, but you may still only put Vehicles or subtypes into the collection within the method.

In general: with super, you can put values of the mentioned type in it, or subtypes. With extends you can retrieve the mentioned type from the collection, or retrieve them as a supertype.

Marko
  • 352
  • 6
  • Thanks for your answer. And later after I asked this question, I found a statement in Core Java Edition 9 the book as "Intuitively speaking, wildcards with supertype bounds let you write to a generic object, while wildcards with subtype bounds let you read from a generic object.". For now, I can only understand it generally like these statements (yous or the book's). Hopefully that one day I can understand it precisely by understanding the JVM and the Java compiler. But I guess that will be very far from now. – cmpltrtok Aug 31 '20 at 03:28
1

This is a Wildcard Capture problem.

TL;DR - when you use a wildcard (be it with super or extends) in the Generic Collection type definition, getting element from that collection and casting it appropriately can be considered safe, while adding element into the collection is not, and this mechanism is implemented for the safety purpose.

Let's examine the example given in the Oracle Documentation, which demonstrates the reason of why this safety is needed (this example uses extends but same principle applies for super):

The code:

import java.util.List;

public class WildcardErrorBad {

    void swapFirst(List<? extends Number> l1, List<? extends Number> l2) {
        Number temp = l1.get(0);
        l1.set(0, l2.get(0)); // expected a CAP#1 extends Number, got a CAP#2 extends Number;
        l2.set(0, temp); // expected a CAP#1 extends Number, got a Number
    }
}

does not compile, as it is attempting an unsafe operation, because, if you will invoke this method as follows:

List<Integer> li = Arrays.asList(1, 2, 3);
List<Double>  ld = Arrays.asList(10.10, 20.20, 30.30);
swapFirst(li, ld);

while List<Integer> and List<Double> both fulfill the criteria of List<? extends Number>, it is clearly incorrect to take an item from a list of Integer values and attempt to place it into a list of Double values.

Another example I liked is given by Jon Skeet, and it looks like this.

You might also want to read this.

Giorgi Tsiklauri
  • 6,699
  • 7
  • 29
  • 54
  • Surely super Vehicle> reads as any type which is a superclass of Vehicle? – matt freake Aug 30 '20 at 09:50
  • I’m just saying the first sentence seems misleading to me. A Car is a type which extends Vehicle. As I understand it, Car would not match super Vehicle>. Happy to be shown to be wrong though – matt freake Aug 30 '20 at 10:00
  • 1
    @mattfreake I actually completely changed my (initially wrong) answer. – Giorgi Tsiklauri Aug 30 '20 at 11:23
  • Hi @GiorgiTsiklauri, thanks for your answer. But my intent of this question is not about wildcard capture for SomeClass> and the helper method, but it is about why an object of the superclass cannot be set into SomeClass super T> although there is a keyword "super" in the wildcard type. – cmpltrtok Aug 31 '20 at 03:32