I have a question regarding generics:
Map<? super String, ? super String> mappa1 = new HashMap<Object,Object>();
with super it's possible to instantiate a HashMap<Object,Object>
for a <? super String>
.
However then you can add only objects which extends String ( in this case only String itself).
Why don't they forbid by compilation error as well as happens with the extends
wildcard.
I mean if once created a Map <Object, Object>
it's possible only to add Strings.. why not forcing to create a Map<String, String>
in the first place? (like it happens with the extends
wildcard)
Again I know the difference between super
and extends
concerning generics. I would like just to know the details I have aboved-mentioned.
Thanks in advance.
Let's use List
instead of Map
for brevity.
Essentially, practical meaning of extends
and super
can be defined as follows:
List<? extends T>
means "a List
you can get T
from"List<? super T>
means "a List
you can put T
into"Now you can see that there is nothing special about extends
- behavior of extends
and super
is completely symmetric:
List<? extends Object> a = new ArrayList<String>(); // Valid, you can get an Object from List<String>
List<? extends String> b = new ArrayList<Object>(); // Invalid, there is no guarantee that List<Object> contains only Strings
List<? super String> a = new ArrayList<Object>(); // Valid, you can put a String into List<Object>
List<? super Object> b = new ArrayList<String>(); // Invalid, you cannot put arbitrary Object into List<String>
I think you are thrown off because you picked a collection type. Collections are rarely used as consumers and thus a lower bound (? super X
) is not put on their element types. A more appropriate example is predicate.
Consider a method such as <E> List<E> filter(List<? extends E> p, Predicate<? super E> p)
. It will take a list l
and a predicate p
and return a new list containing all elements of l
which satisfy p
.
You could pass in a List<Integer>
and a Predicate<Number>
which is satisfied by all multiples of 2.5
. The Predicate<Number>
would become a Predicate<? super Integer>
. If it did not, you could not invoke filter as follows.
List<Integer> x = filter(Arrays.asList(1,5,8,10), Predicates.multipleOf(2.5));
Map<? super String, ? super String> mappa1 = new HashMap<Object,Object>();
Since Java Generics are based on type erasure, with this line you didn't create a MashMap<Object,Object>
. You just created an instance of the HashMap
class; the type parameters get lost immediately after this line of code and all that stays is the type of your mappa1
variable, which doesn't even mention Object
. The type of the new
expression is assignment-compatible with the type of mappa1
so the compiler allows the assignment.
In general, the type parameters used with new
are irrelevant and to address this issue, Java 7 has introduced the diamond operator <>
. All that really matters is the type of mappa1
, which is is Map<? super String, ? super String>
; as far as the rest of your code is concerned, this is the type of the instantiated map.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With