Параметр универсального типа Java не входит в его пределы
Готовясь к экзамену OCPJP 6 (именно поэтому я использую компилятор Java 1.6), я заметил кое-что неясное для меня относительно Java Generics. Рассмотрим следующий код:
class A<K extends Number> {
public <V> V useMe1(A<? super V> a) { // OK
return null;
}
public <V> V useMe2(A<? extends V> a) { // OK
return null;
}
public <V> V useMe3(A<V> a) { // ERROR, but why, since 2 above were ok
return null;
}
}
Когда я пытаюсь скомпилировать код (с компилятором 1.6), я получаю ошибку:
параметр типа V находится за его пределами
Несмотря на непригодность приведенного выше кода, мне интересно, почему компилятор считает, что типы <? super V>
а также <? extends V>
соответствуют типу класса, но <V>
нет (так как V совпадает с обеими границами).
Я не собираюсь изменять этот код, я хочу это понять. Код взят из примера экзаменационного вопроса OCPJP 6 с вопросом "Какая строка будет компилироваться?"
1 ответ
Третий, useMe3
Сбой как V
не гарантируется extend Number
учитывая отсутствие границ на его декларации <V>
, И так как аргумент объявлен как A<V>
нет козла, V
должен продлить Number
и язык Java просит программиста явно заявить об этом в этом случае.
Это на самом деле легко, и, возможно, менее очевидно, почему другие два могут работать. Используя ?
в их определении типа аргумента вы даете шанс того, что он будет совместим с extend Number
даже когда V
сам по себе является монастырем, не ограниченным какой-либо конкретной границей в отношении Number
,
Вы должны заметить, что extend Number
не влияет V
дольше, но ?
что бы это ни было. Еще один способ выразить это, есть неизвестный класс, который представлен этим ?
и должен extend Number
и вдобавок к этому для метода useMe1
например, это должно быть супер V
где V
будет определяться кодом, который вызывает этот метод.
Это, возможно, более интересно в случае useMe2
где V
может быть чем-то совершенно не связанным с Number
, Например:
interface FooInterface { ... }
class MyNumber extends Number implements FooInterface { ... }
A<?> subject = ...;
A<MyNumber> param = ...;
FooInterface foo = subject.useMe2(param);
в useMe2
позвони выше, V
является FooInterface
это не имеет ничего общего с Number
и ?
в этом случае MyNumber
, MyNumber
ограничен A
параметр типа, связанный с extends Number
и определением параметра типа аргумента в useMe2
расширить FooInterface
но V
Сам по себе полностью неограничен.