To jest prawdziwy przykład z interfejsu API biblioteki innej firmy, ale uproszczony.
Skompilowano za pomocą Oracle JDK 8u72
Rozważ te dwie metody:
<X extends CharSequence> X getCharSequence() {
return (X) "hello";
}
<X extends String> X getString() {
return (X) "hello";
}
Obaj zgłaszają ostrzeżenie o „niesprawdzonej obsadzie” - rozumiem dlaczego. Zdumiewa mnie to, dlaczego mogę zadzwonić
Integer x = getCharSequence();
i się kompiluje? Kompilator powinien wiedzieć, że Integer
nie implementuje CharSequence
. Wezwanie do
Integer y = getString();
daje błąd (zgodnie z oczekiwaniami)
incompatible types: inference variable X has incompatible upper bounds java.lang.Integer,java.lang.String
Czy ktoś może wyjaśnić, dlaczego takie zachowanie miałoby zostać uznane za ważne? Jak by to było przydatne?
Klient nie wie, że to wywołanie jest niebezpieczne - kod klienta kompiluje się bez ostrzeżenia. Dlaczego kompilacja nie ostrzegłaby o tym / nie spowodowała błędu?
Czym różni się od tego przykładu:
<X extends CharSequence> void doCharSequence(List<X> l) {
}
List<CharSequence> chsL = new ArrayList<>();
doCharSequence(chsL); // compiles
List<Integer> intL = new ArrayList<>();
doCharSequence(intL); // error
Próba zaliczenia List<Integer>
powoduje błąd, zgodnie z oczekiwaniami:
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
Jeśli jest to zgłaszane jako błąd, dlaczego Integer x = getCharSequence();
tak nie jest?
Integer x = getCharSequence();
będzie się kompilował, ale casting na RHSInteger x = (Integer) getCharSequence();
kończy się niepowodzeniem