1

The other day I wad trouble understand a particular textbook example related to bounded wildcards and how they're used in combination with a Queue.

The example starts by setting up a trivial inheritance hierarchy:

class X {
    int i;
    X(int i) { this.i = i; }
}

class Y extends X {
    int i;
    Y(int i){ this.i = i; }
}

class Z extends Y {
    int i;
    Z(int i) { this.i = i; }
}

The main class hosts a static method that takes a Queue with an upper-bounded wildcard definition and adds a random number of new elements.

public class Wildcards {

    static void rtn(Queue<? extends Y> q) {
        q.add(new Y(5));
        q.add(new Z(5));
    }

    public static void main(String[] args) {
        Queue<Y> q = new LinkedList<>();
        rtn(q);
    }
}

My understanding of this particular wildcard definition is "Allow adding elements to q that are either of type Y or extend from type Y. So q.add(new Y(5)) would be as legal as q.add(new Z(5)). However the compiler is complaining in both cases: Required type: capture of ? extends Y - Provided Y/Z.

I'm struggling to understand this message in this context - I have a hunch that it might not be related to the wildcard definition at all but I'm not sure.

Thanks so much for your help!

MrBr
  • 1,884
  • 2
  • 24
  • 38
  • Does this answer your question? [What is PECS (Producer Extends Consumer Super)?](https://stackoverflow.com/questions/2723397/what-is-pecs-producer-extends-consumer-super) – Amongalen Jun 16 '20 at 11:34

1 Answers1

0

OK, so first off, your class hierarchy is broken - this won't compile. Remember that a base class becomes "part" of your derived class. That means a) you have three different 'i' (one in each class) b) you are not initializing the i in your super class, because you don't have a default constructor (without arguments) and you don't call super(i). Let's fix that:

class X {
    int i;
    X(int i) { this.i = i; }
}

class Y extends X {
    Y(int i) { super(i); }
}

class Z extends Y {
    Z(int i) { super(i); }
}

Now to the actual question: Always remember PECS - Producer extends, Consumer super That means, if you have, e.g., a collection you want to query, i.e., get results out of in a type safe matter, you have to use bounds with extends. If you want to consume values, e.g., put something into a collection, use super.

Why? So "super" and "extends" are upper and lower limits:

For "consumption" <? extends Y> means "I will only accept classes that Y extends and <? super Y> means "I will only accept classes where Y is the super class".

In your case, you write a method, that should accept Queue<Y> or Queue<Z> - so you're saying "My methods should accept Queues of Types where Y is the super type"

This will work:

public class Wildcards {

    static void rtn(Queue<? super Y> q) {
        q.add(new Y(5));
        q.add(new Z(5));
    }

    public static void main(String[] args) {
        Queue<Y> q = new LinkedList<>();
        rtn(q);
    }
}

See https://docs.oracle.com/javase/tutorial/extra/generics/wildcards.html

Benjamin Maurer
  • 3,602
  • 5
  • 28
  • 49