This is a real-world example from a 3rd party library API, but simplified.
Compiled with Oracle JDK 8u72
Consider these two methods:
<X extends CharSequence> X getCharSequence() {
return (X) "hello";
}
<X extends String> X getString() {
return (X) "hello";
}
Both report an "unchecked cast" warning - I get why. The thing that baffles me is why can I call
Integer x = getCharSequence();
and it compiles? The compiler should know that Integer
does not implement CharSequence
. The call to
Integer y = getString();
gives an error (as expected)
incompatible types: inference variable X has incompatible upper bounds java.lang.Integer,java.lang.String
Can someone explain why would this behaviour be considered valid? How would it be useful?
The client does not know that this call is unsafe - the client's code compiles without warning. Why wouldn't the compile warn about that / issue an error?
Also, how is it different from this example:
<X extends CharSequence> void doCharSequence(List<X> l) {
}
List<CharSequence> chsL = new ArrayList<>();
doCharSequence(chsL); // compiles
List<Integer> intL = new ArrayList<>();
doCharSequence(intL); // error
Trying to pass List<Integer>
gives an error, as expected:
method doCharSequence in class generic.GenericTest cannot be applied to given types; required: java.util.List<X> found: java.util.List<java.lang.Integer> reason: inference variable X has incompatible bounds equality constraints: java.lang.Integer upper bounds: java.lang.CharSequence
If that is reported as an error, why Integer x = getCharSequence();
isn't?