Reputation: 337
Why does Java doesn't throw any warning when compiling my TestGenerics
class
, considering that the String
class
is final
and cannot be extended?
import java.util.*;
public class TestGenerics {
public void addStrings(List<? extends String> list) {
// some code here
}
}
}
Upvotes: 13
Views: 1356
Reputation: 19682
The type system does not consider List<String>
and List<? extends String>
equivalent, even though at the time of compiling, String
has no subtypes other than itself, therefore any object that is a List<? extends String>
must also be a List<String>
.
One explanation is that final
is not final - it's ok to remove final
from a class and nothing should break: http://docs.oracle.com/javase/specs/jls/se7/html/jls-13.html#jls-13.4.2
It's not without precedence that the type system takes final
into consideration; for example, we cannot cast a String
to a Runnable
, because the compiler figures that if an object is String
, it cannot be some unknown subclass that implements Runnable
.
If we want generics also to make reasoning like that and deduce that List<String>
and List<? extends String>
are equivalent, it'll make typing rules even more complicated.
Upvotes: 0
Reputation: 43401
Let's say I had a method like this:
public List<? extends T> filterOutNulls(List<T> input) { ...
Granted, not the best signature in the world, but still perfectly legal. What would happen if I passed a List<String>
to that method? According to the signature, it returns a List<? extends String>
. If Java disallowed that type, it'd be impossible to use this method for List<String>
(or at least, it'd be impossible to use the return value).
Secondarily, the extends
syntax is still useful in this case, since List<String>
and List<? extends String>
have different restrictions -- specifically, you can't add anything but a null
literal to List<? extends String>
. I'll sometimes use ? extends
to signify that a collection is read-only (since the only T
s you can pass in are null
), and ? super
to signify write-only (since you can only get out T
s as Object
). This isn't completely fool-proof (you can still call remove methods, pass in null
s, downcast, etc) but serves as a gentle reminder of how the collection is probably meant to be used.
Upvotes: 12
Reputation: 17007
The compiler doesn't really take note of that fact, because it doesn't matter. String
s are still allowed in the list, and in the final product, the possibility of anything extending String
is not found. After erasure, it comes out like this:
public void addStrings(List list)
As you can see, there is now no suggestions of a class extending String
. If you do create a class extending String
, that will be itself a compile error. There's no need for javac to worry about that.
Upvotes: 7