Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

If Java String extends Object then why cant it be passed to <? extends Object> type

For example why doesn't the following work?

Map<String, ? extends Object> table = new HashMap<>();
table.put("K", "V"); //Error V cannot be applied to ? extends String.

However String must extend Object, why does the above throw compiler error?

The IntelliJ error I get is

Wrong 2nd Argument Type. Found 'java.lang.String'required: '? extends java.lang.Object'

However the following works:

Map<String, ? super Object> table = new HashMap<>();
table.put("K", "V"); //Error V cannot be applied to ? extends String.

Now the above is truly weird. How can a lowerbound work on Object class?

I mean doesn't

? super Object

mean an "Unknown that is superclass of Object"?

AFAIK Object is at root of Java class hierarchy.

like image 375
Ace Avatar asked Apr 25 '17 18:04

Ace


1 Answers

Because ? extends Object does not mean "any type that extends Object." It means "some specific type, which we don't know what it is, as long as it extends Object." The difference is subtle, but significant!

The following code compiles totally fine:

Map<String, Integer> stringToInteger = new HashMap<>();
Map<String, ? extends Object> stringToWildcard = stringToInteger;

It makes sense that that would compile. stringToWildcard is a map whose value is "some type ... as long as it extends Object" -- and Integer is a type that extends object.

So, given that, imagine if your table.put("K", "V") worked. We could do this:

Map<String, Integer> stringToInteger = new HashMap<>();

Map<String, ? extends Object> stringToWildcard = stringToInteger;
stringToWildcard.put("K", "V");

Integer value = stringToInteger.get("K");

This would result in a ClassCastException on the last line, since the string "V" can't be cast to an Integer.

Instead, the compiler will disallow table.put("K", "V"). What it's telling you is: "hey, the value needs to be some specific type. I don't know what that type is, other than that it extends Object. But I can't let you put a String in, because I don't know if that type is String."

like image 158
yshavit Avatar answered Sep 22 '22 00:09

yshavit