1

Having the below code:

    Stack<Integer> integers = new Stack<Integer>();
    Stack<? extends Number> numbers = integers;
    Number n = numbers.pop();
    numbers.push(3);
    numbers.push(n);

I get compilation errors on the last two lines, but although I've given it some thought I don't understand why the compilation errors are there.

The method push(capture#2-of ? extends Number) in the type Stack<capture#2-of ? extends Number> is not applicable for the arguments (int)

When I comment the last line, I still get the above compilation error, but from my understanding the compiler should be able to infer the correct type (Stack) from those lines.

Thanks a lot

2
  • please check the other questions at SO, there are lots of similar questions to this one.
    – Augusto
    Commented Jun 25, 2011 at 7:52
  • I've searched through 5-10 of them and they seem to be about how to cast List<? extends Number> to List<Integer> and similar. I'll go and have a closer look though
    – yas4891
    Commented Jun 25, 2011 at 7:58

3 Answers 3

2

The last two lines aren't valid because numbers could be a stack of any numeric type. Consider this similar code:

Stack<Double> doubles = new Stack<Double>();
Stack<? extends Number> numbers = doubles;
Number n = numbers.pop();
numbers.push(3);
numbers.push(n);

Here you're trying to put an Integer onto a Stack<Double> which obviously isn't correct.

Basically when you use wildcarding like this, you can get values out, but you can't put values in because the compiler can't guarantee it's valid to do so.

2
  • From reading this and the link provided by @Cris I seem to understand the problem at hand. However, why can't the compiler infer the type, when there is only one element (of type Integer) pushed onto the stack?
    – yas4891
    Commented Jun 25, 2011 at 8:04
  • @yas4891: The compiler isn't meant to infer anything from the previous lines of code - only from the type of the variable, which is Stack<? extends Number>.
    – Jon Skeet
    Commented Jun 25, 2011 at 8:15
2

Generics covariance in Java is handled at the client. i.e. You don't have the semantics to say that a Stack is covariant and let the compiler check that the operations you are allowing (like push) is valid in a covariance model. (push is not).

The specific issue here is that you can do something like this:

Number r = new Rational(a,b); // rationals are also numbers
number.push(r);

which in the underlying structure implies integer.push(r); // type mismatch

(Programming in Scala has a crystal clear explanation of client vs provider side (co-/contra-)variance on Chapter 19. A recommended read even if you are not into Scala)

1

very clear answer here How can I add to List<? extends Number> data structures?

2
  • well sometimes is easier to redirect to an already existing well documented response. please give credit to that response :)
    – Cris
    Commented Jun 25, 2011 at 8:08
  • alos guys from here that spend their time to help you more then me...deserve that :)
    – Cris
    Commented Jun 25, 2011 at 8:09

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.