Подстановочный знак и тип границ pameter в Java
Рассмотрим этот случай:
class A {}
class B<T extends A, E extends T> {
B<?, A> b;
B<?, ? extends A> b2;
}
Как я понимаю границы типа, в этом случае эффективные верхние границы обоих T
а также E
является class A
, Итак, вопрос: почему javac не принимает класс A в качестве аргумента в объявлении поля b
, но принимает wildcard
? extends A
в объявлении поля b2
?
3 ответа
Со следующими классами:
class A {}
class C extends A {}
class B<T extends A, E extends T> {}
Думайте об этом так:
E extends T extends A
С B<?,A>
затем T -> ?
а также E -> A
A extends ? extends A
Где ?
может быть любой подкласс A
скажем C
,A extends C extends A
явно недействительным.
Вот почему это ошибка компиляции.
Примечание для пользователей Eclipse:
Компилятор Eclipse 4.9.0 не согласился с javac 8u и Intellij и не выдал ошибку компиляции для общих аргументов в B<?,A>
, Я предполагаю, что это ошибка в компиляторе Eclipse, но я не обращался к JLS, чтобы подтвердить это.
class B<T extends A, E extends T> {
B<?, A> b; // <-- Eclipse does NOT emit a compile error
B<?, ? extends A> b2;
}
Об этой предполагаемой ошибке сообщалось здесь.
Ваша декларация неверна. Вы упускаете точку "подстановочных знаков". Они используются для объявления неизвестного свойства. За B<?, E> b
E
должен продлить T
и T
должен продлить A
но вы сказали, что первый общий тип ?
что неизвестно! Итак, вы сказали, что неизвестный параметр должен быть расширен T
так что A
, Это неверно.
Отношения, которые вы создали, похожи E -> T -> A
, После этого вы объявили 1. универсальный тип ? -> E -> T -> A
и 2. универсальный тип как A -> E -> T -> ?
, Так? должен распространяться? и A должен расширять E против. Это сбивает с толку и неизвестно для компилятора...
В вашей декларации поля b
, тип T
может быть что угодно A
, В очереди E
должен продлить T
Однако вы предоставляете тип A
за T
, A
не будет подклассом чего-то, что является подклассом A
,