2

take the following code:

 public class Main {

    public static void main(String[] args) {
        List<Object> list1 = new ArrayList<Object>();
        List<? super Integer> list2 = list1;
        list2.add(1);
        list1.add("two");
        //list2.add("three"); // will never compile!!.
        System.out.println("list1:  " + list1.toString());
        System.out.println("list2:  " + list2.toString());

    }

}

here is the output:

list1:  [1, two]
list2:  [1, two]

on the one hand, list2 doesn't allow the add() method on objects like the String "three"; but on the other hand it references a List containing Objects.

Kachna
  • 2,701
  • 2
  • 17
  • 30
  • 2
    Can you clarify what the actual question is? I'm assuming it's something like "How can list2 appear to contain a string (in the print statement) when its type is `? super Integer`, especially given that adding a string to it as `list2.add("three")` won't compile?" but all you've really given is an observation. – alexroussos May 10 '15 at 23:23
  • What you have is a list of valid assignments that may look strange if you don't think about the sequence it is processed in. At the point of you assigning `list2 = list1;` it is perfectly valid, even at a later point you can add new entry (to both lists as they are in fact one single list) by `list1.add("three");` There is nothing strange and unusual about it – Germann Arlington May 11 '15 at 00:17

1 Answers1

3

The compiler doesn't care what kind of objects the list instance accepts. At byte code level any reference is accepted because of type erasure. It just knows about two variables with a List type parameterized with a particular generic type. That one of these variables is assignable to the other is something that is checked and then forgotten.

So when you try to add "three" it looks at the generic type that is accepted by the type of list2, sees it doesn't match, and throws a compile error.

As for the program: there isn't any problem. If you want to restrict the objects you want to add or remove from the list through a variable reference then that is up to you.

Note that it is impossible to retrieve a String from the list referenced by the variables without a cast.

Maarten Bodewes
  • 80,169
  • 13
  • 121
  • 225
  • I agree thought that this kind of thing is *far* from intuitive and I'm not a big fan of the current setup with regards to generics. – Maarten Bodewes May 11 '15 at 00:37
  • Could you explain why `list2.add(new Object());` does not compile, as `Object` is clearly a super type of `Integer`? Shouldn't you be able to _add_ any super type, but only _get_ an `Integer` without casting? – Mick Mnemonic May 11 '15 at 00:57
  • I can only explain this through a [reference to another question](http://stackoverflow.com/q/3847162/589259). It's kind of the same, but without the assignment from `list1` to `list2`. As said, this is not intuitive to me either. – Maarten Bodewes May 11 '15 at 01:03
  • 1
    Yea, this is rather unintuitive. For me, [this answer](http://stackoverflow.com/a/4343547/905488) helped to clarify the problem better. In short, you cannot make the list addition I suggested, because `list2` could have a run-time type of `ArrayList`. My assumption was backwards; you can only _add_ sub-types of the parameterized type (or the type itself), and you can only _get_ `Object`s, when using lower bounded wildcards. Producer Extends, Consumer Super (PECS): a list of type `List super Integer>` can only _consume_ `Integer`s (and sub-types of `Integer`s). – Mick Mnemonic May 11 '15 at 01:47
  • `List super Integer>` refers to a list that accepts some _unknown but specific_ supertype of `Integer`. For example, `List super Integer> list = new ArrayList()` compiles, and that list cannot accept anything but `Integer`. – Louis Wasserman May 11 '15 at 05:38
  • A source of confusion (probably for the OP as well) is that `List super Integer> list = new ArrayList()` also compiles, but you cannot `add` anything but `Integer`s to that list either because of the way it has been declared with the lower bounded wildcard. So I think it's misleading to say that the list can "accept" any supertypes of `Integer`s, because it can only consume objects having a type whose upper bound is `Integer`. The types of objects "accepted" from a read/write context are different (as pointed out in the linked answer). – Mick Mnemonic May 11 '15 at 07:55
  • @LouisWasserman Although my answer I think is correct I would be very happy to upvote a better one from you - feel free to update as well. – Maarten Bodewes May 12 '15 at 10:30