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.
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."
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