(Чтобы прояснить вопрос, 'T' относится к параметру типа, объявленному в Class)
В качестве примера, пожалуйста, просмотрите следующее приложение:
public class TestClass {
interface InterfaceA{}
interface InterfaceB{}
interface InterfaceC{}
class ClassA implements InterfaceA, InterfaceB, InterfaceC{}
public static void main(String[] args){
Class<? super ClassA> superClass1 = ClassA.class;
Class<? super ClassA> superclass2 = InterfaceA.class;
Class<? super ClassA> superclass3 = InterfaceB.class;
Class<? super ClassA> superclass4 = InterfaceC.class;
for(Class<?> clazz : ClassA.class.getInterfaces()){
System.out.println(clazz.getName());
}
}
}
Результат - то, что можно ожидать:
TestClass$InterfaceA
TestClass$InterfaceB
TestClass$InterfaceC
Итак, основываясь на этом примере выше, мы можем видеть, что компилятор распознает, что InterfaceA соответствует , что соответствует границам подстановочного знака, как и все другие интерфейсы.
Интуитивно, я бы ожидал, что следующее будет безопасным, но это не так:
Class<? super ClassA>[] interfaces = ClassA.class.getInterfaces();
Компилятор выдает предупреждение, потому что подпись говорит, что он возвращает Class; однако в Javadoc для Class указано следующее:
Если этот объект представляет класс, возвращаемое значение является массивом
содержащие объекты, представляющие все интерфейсы, реализованные
класс.
«Этот объект» в нашем случае относится к ClassA
. На основании этого заявления, если мы позвоним:
ClassA.class.getInterfaces()
тогда мы знаем, логически, что каждый Class<?>
в возвращенном массиве будет содержать ссылку на супер тип ClassA
.
В качестве дополнительной справочной информации:
Из справочника по языку Java, третье издание:
Класс обязательно реализует все интерфейсы, которые он направляет
суперклассы и прямые суперинтерфейсы делают. Этот (множественный) интерфейс
наследование позволяет объектам поддерживать (множественное) общее поведение
без совместного использования.
Читая эту и другие части спецификации, я думаю, что любой класс или интерфейс, реализованный или расширенный классом T
, попадет в границы <? super T>
.
РЕДАКТИРОВАНИЕ:
Было высказано предположение, что нет конкретной причины для моего вопроса. Я приведу пример:
1 import java.util.Map;
2 import java.util.HashMap;
3
4 public class MapWrapper<T> {
5 private final Map<Class<?>, OtherClass<T,?>> map = new HashMap <Class<?>, OtherClass<T,?>>();
6
7 public <W> void addToMap(Class<W> type, OtherClass<T,? super W> otherClass){
8 map.put(type, otherClass);
9 }
10
11 public <W> OtherClass<T,? super W> getOtherClassForAnyInterface(Class<W> type){
12 if(type.getInterfaces()!=null){
13 for(Class<?> interfaceType : type.getInterfaces()){
14 // Here, a cast is necessary. It throws a compiler warning for unchecked operations (rightfully so)
15 OtherClass<T,? super W> otherClass = (OtherClass<T,? super W>)getOtherClassForInterface(interfaceType);
16 if(null!=otherClass){
17 return otherClass;
18 }
19 }
20 }
21 return null;
22 }
23
24
25 public class OtherClass<T,V> {}
26
27 }
Проблема в строке 15. Вы должны привести к <? super W>
, чтобы получить правильный тип. Предупреждение компилятора может быть подавлено, но оправдано ли это? Есть ли какой-то сценарий, когда этот акт не соответствует действительности?