1

So I was revising some Java concepts and i found out i don't completly understand generics in the most 'complicated' cases. I have around 3 months of Java classes and an exam soon so I would appreciate any help!

In the attached example i dont get why 1) and 2) are invalid.

Thanks in advance!

enter image description here

ernest_k
  • 44,416
  • 5
  • 53
  • 99
julio cas
  • 13
  • 3
  • 2
    For future: please do not paste images with code! – Pijotrek Jun 21 '18 at 09:51
  • Oh got it, thanks! I'm new here so any help is greatly appreciated! – julio cas Jun 21 '18 at 09:52
  • 2
    Possible duplicate of [Covariance, Invariance and Contravariance explained in plain English?](https://stackoverflow.com/questions/8481301/covariance-invariance-and-contravariance-explained-in-plain-english) – ollaw Jun 21 '18 at 09:54
  • Possible duplicate of [What does the question mark in Java generics' type parameter mean?](https://stackoverflow.com/questions/3009745/what-does-the-question-mark-in-java-generics-type-parameter-mean) – Neijwiert Jun 21 '18 at 09:55
  • new Set()? what? That code is also invalid, you can't instantiate an interface – Coder-Man Jun 21 '18 at 09:57
  • I understand what the ? means i just don't understand what assignments are allowed and why the others aren't. – julio cas Jun 21 '18 at 09:57
  • @POrekhov The code ist most likely copied of a textbook or something and used to understand the **conecept** of generics. Not the instantiation of a `Set`.It has nothing to do with the real issue. – L.Spillner Jun 21 '18 at 09:59
  • @POrekhov my bad, in this example i have noted in my papers that Set is a user defined class that the teacher created to show these examples. Its "public class Set { (...) }" – julio cas Jun 21 '18 at 10:00

1 Answers1

2

You can think about this quite easily. A List<? extends SomeClass> will always produce an implementation of SomeClass. See the following example:

List<Integer> ints = new Arrays.asList(1,2,3,4);
List<? extends Number> nums = ints; // this does work
Integer i = nums.get(0); // this doesn't
Number num = nums.get(0); // this does again
nums.add(5); // this doesn't too

You see that nums holds a reference to ints. Because Integer extends Number. And if you read the nums-list you'll always get a Number out.

This holds true for every superclass-subclass relationship.

But: you can't write to the nums list. That is, because you don't exactly know what list actually is referenced by nums in the above example it was a list of Integers, you just know what to expect from the list when you read it.


The same is for List<? super SomeClass> which is the invert of the above. It will always consume any implementations of SomeClass. See again the example:

List<Object> objs = new ArrayList<>();
List<? super String> strings = objs; // this does work
strings.add("Some String"); // this works
String string = strings.get(0); // this doesn't
Object object = strings.get(0); // this does again

Now we only know that every element of type String and more specific can be put into the Strings list. As this is the invert of the above. You don't know what you will get, if you try to read the list. You can just read Objects but you will never know their actual class.


This is generally called PECS, which stands for: Producer extends Consumer super. More about this topic can be read in this question

Lino
  • 19,604
  • 6
  • 47
  • 65
  • 1
    First of all, thanks for taking your time into answering this so well! So if i have a "List extends SomeClass> list" i cannot add ANYTHING into that list ? I can only make the list = someListThatExtendedSomeClass ? This seems bad for most applications, no ? The same going for the super, if we can only add to those lists, how do we read from them? Edit: after carefully reading the PECS question you linked i think i got it. This is used when we want our methods to be more flexible but outside those methods we do know what the list holds and can act on that. – julio cas Jun 21 '18 at 10:20
  • @juliocas thats right. You commonly don't instantiate a list with extends or super. As you said you accept those lists, or any other generix class mostly in methods. This makes also your intentions clear, what you're doing with that passed in list. If the parameter uses `? extends` then you explicitly say that you only want to read, and the other way arround with `? super` of course – Lino Jun 21 '18 at 10:28
  • Just one more thing, In the last line of the example, why am i not allowed to store an Object in the set ? – julio cas Jun 21 '18 at 10:51
  • @juliocas A `Set extends Number>` doesn't know what implementation it holds. It could hold a `Set`, but also a `Set`. So the compiler doesn't really know what *exactly* is stored, he just knows what to expect *at least* from the set. I hope this answers your question – Lino Jun 21 '18 at 10:54
  • The example was `Set super Integer> set = new Set();` and then `set.add(1.0); // INVALID!!!` and `set.add(new Object()); //INVALID!!!` Not being able to put the double in there i get but shouldnt the object be allowed? – julio cas Jun 21 '18 at 11:03
  • @juliocas No, because you still have an implementation of a `new Set()` right? You're not allowed to write an `Object` to `Set extends Integer>` as you're not allowed to write said object to a simple `Set` – Lino Jun 21 '18 at 11:11
  • Oh i get it, having a `Set super Integer>` means that i can be a Set, not that it can store Object objects in it. Thank you so much! – julio cas Jun 21 '18 at 11:13
  • @juliocas glad I could help you understand this. I myself had really problems with this in the beginning :) – Lino Jun 21 '18 at 11:16