2

EquilateralTriangle is a subtype of Triangle.

List<? super EquilateralTriangle> equilateralTriangle =
        new ArrayList<Triangle>(Arrays.asList(new Triangle(), new Triangle()));
equilateralTriangle.add(new Triangle());            // doesn't work
equilateralTriangle.add(new EquilateralTriangle()); // works

As far as I know List<? super EquilateralTriangle> is the declaration and with new ArrayList<Triangle> we are telling something concrete to the compiler that my arraylist is of type triangle. Then why does compiler complain on the second line? I'm inserting the same value as I defined in the type parameter defined while instantiating arraylist.

Java arraylist definition says this:

class ArrayList<E> extends AbstractList<E>

public ArrayList(Collection<? extends E> c)

and boolean add(E e); for ArrayList.

So, the type E can be infered as Triangle. Then add must not complain as I'm passing the Triangle as I did in ArrayList constructor. What is missing in my understanding?

Paul Bellora
  • 54,340
  • 18
  • 130
  • 181
Curious
  • 921
  • 1
  • 9
  • 25
  • The add method's parameter is in contravariant position, I think that is the reason why it does not work. – Gábor Bakos Mar 22 '14 at 13:51
  • http://stackoverflow.com/questions/2776975/how-can-i-add-to-list-extends-number-data-structures and several others. You can't add to that list type after you assign it; `?` means *unknown*. You're adding to a known list on line 1. – Brian Roach Mar 22 '14 at 14:03
  • Hi Brian that is true in case of List extends Number> foo3 example because you don't know exactly which type and is family of the types thats what wild cards say. But I used super E>, if that is the case why equilateralTriangle.add(new EquilateralTriangle()); **is working** – Curious Mar 22 '14 at 14:20
  • Thanks Brain I think I got it. It worked because you are adding Triangle which is the super type of EquilateralTriangle. But how compiler knows that which super type. But as you defined ? super EquilateralTriangle that means compiler is pretty sure as you defined in declaration type parameter.Thanks for the comment. – Curious Mar 22 '14 at 14:24

2 Answers2

1

Take a look at the following statements. Obviously, adding a String works whereas adding an Object causes a compile-time error.

List<String> items = ...;
items.add(new String()); // works
items.add(new Object()); // error

Now, let's use a wildcard as in your question:

List<? super String> items = ...;

In this variable declaration, the ? stands for an unknown type, that is either String or a base class of String. The type is not deduced/inferred. It is just an unknown type. The compiler must assume, that ? super String can be String. And as we have seen above, you are not supposed to add Objects into a list of Strings.

nosid
  • 48,932
  • 13
  • 112
  • 139
0

nosid's answer explains the contravariance part. I'll just address this question:

why does compiler complain on the second line? I'm inserting the same value as I defined in the type parameter defined while instantiating arraylist.

I could ask you the same question about this code:

Object object = new ArrayList<Triangle>();
object.add(new Triangle());

Why doesn't this work? Doesn't the compiler know that object is an ArrayList<Triangle>?

The answer is no. It doesn't matter to the compiler what type was instantiated. What matters is the type of the variable that you call add on.

Community
  • 1
  • 1
Paul Bellora
  • 54,340
  • 18
  • 130
  • 181