Reputation: 13108
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.
Upvotes: 5
Views: 2208
Reputation: 242686
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>
Upvotes: 6
Reputation: 6181
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));
Upvotes: 4
Reputation: 200148
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.
Upvotes: 2
Reputation: 8928
The problem you're describing doesn't exist.
It is because your reference is declared as Map<? super String, ? super String>
. But your actual object can hold any object since it's HashMap<Object,Object>
Map<? super String, ? super String> mappa1 = new HashMap<Object,Object>();
map1.put("", "");
//you can put only string to map1
//but you can do this
Map map2 = map1;
map2.put(23, 234);
the same can be described by a better example:
String a = "a".
a.length(); // legal.
Object b = a;
b.length() // compilation error
Upvotes: 0