Reputation: 15331
In Java generics, if you type
List<Object> l = new ArrayList<>();
List<String> l2 = l; //no casting works here
It won’t compile, reporting inconvertible types List<Object> to List<String>
. However:
List<? extends Object> l = new ArrayList<>();
List<String> l2 = ( List<String> ) l;
List<String> l3 = ( List<String> ) l;
Does work. Why is that the case?
Upvotes: 0
Views: 127
Reputation: 5705
List<Object> l = new ArrayList<>();
List<String> l2 = l; //no casting works here
It doesn't work because you are assigning List<Object>
to List<String>
however these are incompatible types;
List<? extends Object> l = new ArrayList<>();
List<String> l2 = ( List<String> ) l;
List<String> l3 = ( List<String> ) l;
This works because, at compile time it checks that List<? extends Object>
can be casted to List<String>
When we don't use extends
keyword the types are expected to be exact.
Upvotes: 2
Reputation: 88707
That's because List<? extends Object>
might actually refer to a List<String>
and thus the compiler has to trust the developer.
In the first case the compiler knows that the cast will mess with the assumptions other code will have (i.e. that you can put every kind of object into l
and that l2
will only contain strings) and thus is able to refuse the cast.
The same (or something similar) happens with plain objects:
Integer i = new Integer(1);
String s = (String)i;
The above will fail because the compiler knows that an Integer
object can't possibly be cast to String
.
However, the following at least compiles since the compiler doesn't know the actual type of i
(think of i
coming from elsewhere in your code) and thus the compiler has to trust you know what you're doing.
Object i = new Integer(1);
String s = (String)i;
Upvotes: 3