Rollerball
Rollerball

Reputation: 13108

Detail about the "super" wildcard in java generics

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

Answers (4)

axtavt
axtavt

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

Ben Schulz
Ben Schulz

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

Marko Topolnik
Marko Topolnik

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

Tala
Tala

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

Related Questions